diff mbox

MIPS64 user mode emulation Patch

Message ID BANLkTinXJEsQ2+xGr5+sO4uv2L4qXxp-cQ@mail.gmail.com
State New
Headers show

Commit Message

Khansa Butt March 26, 2011, 6:58 a.m. UTC
From cd88be1263d0fc9802cd4dd358ed0299c0d106b0 Mon Sep 17 00:00:00 2001
From: Khansa Butt & Ehsan-ul-Haq <khansa@kics.edu.pk>
Date: Sat, 26 Mar 2011 11:53:11 +0500
Subject: [PATCH] MIPS64 user mode emulation in QEMU
 This patch adds support for Cavium Network's
 Octeon 57XX user mode instructions.  Octeon
 57xx is based on MIPS64.  So this patch is
 the first MIPS64 User Mode Emulation in QEMU
 This is the team(Khansa Butt, Ehsan-ul-Haq, Abdul Qadeer, Abdul Waheed)
 work of HPCNL Lab at KICS-UET Lahore.


Signed-off-by: Khansa Butt <khansa@kics.edu.pk>
---
 configure                             |    1 +
 default-configs/mips64-linux-user.mak |    1 +
 exec.c                                |    1 +
 linux-user/elfload.c                  |   15 +-
 linux-user/main.c                     |   20 +-
 linux-user/mips64/syscall.h           |    2 +
 linux-user/signal.c                   |    3 +-
 linux-user/syscall.c                  |    2 +
 target-mips/cpu.h                     |   16 +
 target-mips/translate.c               |  659
++++++++++++++++++++++++++++++++-
 10 files changed, 704 insertions(+), 16 deletions(-)
 create mode 100644 default-configs/mips64-linux-user.mak

     OPC_BNE      = (0x05 << 26),
     OPC_BNEL     = (0x15 << 26),
@@ -265,6 +279,31 @@ enum {
     OPC_MADD     = 0x00 | OPC_SPECIAL2,
     OPC_MADDU    = 0x01 | OPC_SPECIAL2,
     OPC_MUL      = 0x02 | 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,
+/**************************************/
     OPC_MSUB     = 0x04 | OPC_SPECIAL2,
     OPC_MSUBU    = 0x05 | OPC_SPECIAL2,
     /* Loongson 2F */
@@ -483,7 +522,7 @@ enum {
 static TCGv_ptr cpu_env;
 static TCGv cpu_gpr[32], cpu_PC;
 static TCGv cpu_HI[MIPS_DSP_ACC], cpu_LO[MIPS_DSP_ACC],
cpu_ACX[MIPS_DSP_ACC];
-static TCGv cpu_dspctrl, btarget, bcond;
+static TCGv cpu_dspctrl, btarget, bcond, mpl0, mpl1, mpl2, p0, p1, p2;
 static TCGv_i32 hflags;
 static TCGv_i32 fpu_fcr0, fpu_fcr31;

@@ -779,7 +818,9 @@ static inline void gen_op_addr_add (DisasContext *ctx,
TCGv ret, TCGv arg0, TCGv
        See the MIPS64 PRA manual, section 4.10. */
     if (((ctx->hflags & MIPS_HFLAG_KSU) == MIPS_HFLAG_UM) &&
         !(ctx->hflags & MIPS_HFLAG_UX)) {
-        tcg_gen_ext32s_i64(ret, ret);
+        /*This function sign extend 32 bit value to 64 bit, was causing
error
+          when ld instruction came.Thats why it is commmented out*/
+       /* tcg_gen_ext32s_i64(ret, ret);*/
     }
 #endif
 }
@@ -1419,7 +1460,33 @@ static void gen_arith_imm (CPUState *env,
DisasContext *ctx, uint32_t opc,
     (void)opn; /* avoid a compiler warning */
     MIPS_DEBUG("%s %s, %s, " TARGET_FMT_lx, opn, regnames[rt],
regnames[rs], uimm);
 }
-
+#if defined(TARGET_MIPS64)
+/*set on equal immidiate/seton not equal immidiate*/
+static void gen_set_imm(CPUState *env, uint32_t opc, int rt, int rs,
int16_t imm)
+{
+    target_ulong uimm;
+    TCGv t0, t1;
+    const char *opn = "imm set";
+    uimm = (uint16_t)imm;
+    t0 = tcg_temp_new();
+    t1 = tcg_temp_new();
+    switch (opc) {
+    case OPC_SEQI:
+        tcg_gen_xori_tl(cpu_gpr[rt], cpu_gpr[rs], uimm);
+        gen_load_gpr(t0, rt);
+        tcg_gen_setcondi_tl(TCG_COND_LTU, cpu_gpr[rt], t0, 1);
+        opn = "seqi";
+        break;
+    case OPC_SNEI:
+        tcg_gen_xori_tl(cpu_gpr[rt], cpu_gpr[rs], uimm);
+        gen_load_gpr(t0, rt);
+        gen_load_gpr(t1, 0);
+        tcg_gen_setcond_tl(TCG_COND_LTU, cpu_gpr[rt], t1, t0);
+        opn = "snei";
+        break;
+    }
+}
+#endif
 /* Logic with immediate operand */
 static void gen_logic_imm (CPUState *env, uint32_t opc, int rt, int rs,
int16_t imm)
 {
@@ -1583,13 +1650,196 @@ static void gen_shift_imm(CPUState *env,
DisasContext *ctx, uint32_t opc,
     MIPS_DEBUG("%s %s, %s, " TARGET_FMT_lx, opn, regnames[rt],
regnames[rs], uimm);
     tcg_temp_free(t0);
 }
+#if defined(TARGET_MIPS64)
+/* Addition and carry detection*/
+static void gen_addc (TCGv arg1, TCGv arg2, TCGv res, TCGv c)
+{
+    tcg_gen_add_tl(res, arg1, arg2);
+    tcg_gen_setcond_tl(TCG_COND_LTU, c, res, arg1);
+}
+static void gen_LMI (CPUMIPSState *env, DisasContext *ctx, uint32_t opc,
+                 int rs, int rt, int rd)
+{
+    const char *opn = "LMI";
+    TCGv t0, t1;
+    int nomul = env->CvmCtlRegister.cvmctl & 0x8000000;
+    if (!nomul) {
+        switch (opc) {
+        case OPC_MTM0:
+            tcg_gen_mov_tl(mpl0, cpu_gpr[rs]);
+            tcg_gen_movi_tl(p0, 0);
+            tcg_gen_movi_tl(p1, 0);
+            tcg_gen_movi_tl(p2, 0);
+            opn = "mtm0";
+            break;
+        case OPC_MTM1:
+            tcg_gen_mov_tl(mpl1, cpu_gpr[rs]);
+            tcg_gen_movi_tl(p0, 0);
+            tcg_gen_movi_tl(p1, 0);
+            tcg_gen_movi_tl(p2, 0);
+            opn = "mtm1";
+            break;
+        case OPC_MTM2:
+            tcg_gen_mov_tl(mpl2, cpu_gpr[rs]);
+            tcg_gen_movi_tl(p0, 0);
+            tcg_gen_movi_tl(p1, 0);
+            tcg_gen_movi_tl(p2, 0);
+            opn = "mtm2";
+            break;
+        case OPC_MTP0:
+            tcg_gen_mov_tl(p0, cpu_gpr[rs]);
+            opn = "mtp0";
+            break;
+        case OPC_MTP1:
+            tcg_gen_mov_tl(p1, cpu_gpr[rs]);
+            opn = "mtp1";
+            break;
+        case OPC_MTP2:
+            tcg_gen_mov_tl(p2, cpu_gpr[rs]);
+            opn = "mtp2";
+            break;
+        case OPC_VMM0:
+            t0 = tcg_temp_new();
+            t1 = tcg_temp_new();
+            gen_load_gpr(t1, rs);
+            gen_helper_dmultu(t1, mpl0);
+            gen_load_gpr(t0, rt);
+            tcg_gen_add_tl(t0, t0, cpu_LO[0]);
+            tcg_gen_add_tl(t0, t0, p0);
+            gen_store_gpr(t0, rd);
+            tcg_gen_mov_tl(mpl0, cpu_gpr[rd]);
+            tcg_gen_movi_tl(p0, 0);
+            tcg_gen_movi_tl(p1, 0);
+            tcg_gen_movi_tl(p2, 0);
+            tcg_temp_free(t0);
+            tcg_temp_free(t1);
+            opn = "vmm0";
+            break;
+        case OPC_VMULU:
+            {
+                TCGv t2, c;
+                t0 = tcg_temp_new();
+                t1 = tcg_temp_new();
+                t2 = tcg_temp_new();
+                c = tcg_temp_new();
+                gen_load_gpr(t1, rs);
+                gen_load_gpr(t2, rt);
+                gen_helper_dmultu(t1, mpl0);
+                tcg_gen_mov_tl(t0, cpu_LO[0]);
+                /*if carry comes due to addition of rt and LO register,
+                 * this carry should be added to HI register.
+                 */
+                gen_addc(t0, t2, t1, c);

+                tcg_gen_add_tl(cpu_HI[0], cpu_HI[0], c);
+                /* t0 = t1 + p0 where t1 = LO+rt*/
+                gen_addc(t1, p0, t0, c);
+                tcg_gen_add_tl(cpu_HI[0], cpu_HI[0], c);
+
+                tcg_gen_mov_tl(cpu_gpr[rd], t0);
+                tcg_gen_mov_tl(p0, cpu_HI[0]);
+                tcg_temp_free(t0);
+                tcg_temp_free(t1);
+                tcg_temp_free(t2);
+                opn = "vmulu";
+                break;
+            }
+        case OPC_V3MULU:
+            {
+                TCGv temp[4];
+                TCGv c;
+                TCGv trs, trt, tc1, tc2, tc3;
+                temp[0] = tcg_temp_new();
+                temp[1] = tcg_temp_new();
+                temp[2] = tcg_temp_new();
+                temp[3] = tcg_temp_new();
+                trs = tcg_temp_new();
+                trt = tcg_temp_new();
+                tc1 = tcg_temp_new();
+                tc2 = tcg_temp_new();
+                tc3 = tcg_temp_new();
+                c = tcg_temp_new();
+                gen_load_gpr(trs, rs);
+                gen_load_gpr(trt, rt);
+                /* rs × (MPL2 || MPL1 || MPL0) (192X64 bit multiplication)
*/
+                gen_helper_dmultu(trs, mpl0);
+                tcg_gen_mov_tl(temp[0], cpu_LO[0]);
+                tcg_gen_mov_tl(temp[1], cpu_HI[0]);
+
+                gen_helper_dmultu(trs, mpl1);
+                tcg_gen_mov_tl(temp[2], cpu_HI[0]);
+                gen_addc(cpu_LO[0], temp[1], tc1, tc2);
+                gen_addc(temp[2], tc2, tc3, c);
+                tcg_gen_mov_tl(temp[1], tc1);
+                tcg_gen_mov_tl(temp[2], tc3);
+                tcg_gen_mov_tl(temp[3], c);
+
+                gen_helper_dmultu(trs, mpl2);
+                tcg_gen_add_tl(temp[3], temp[3], cpu_HI[0]);
+                gen_addc(cpu_LO[0], temp[2], tc1, tc2);
+                tcg_gen_mov_tl(temp[2], tc1);
+                tcg_gen_add_tl(temp[3], temp[3], tc2);
+                /* Addition of rt in 256 bit result
+                  (t3 t2 t1 t0 contain result) */
+                gen_addc(temp[0], trt, tc1, c);
+                tcg_gen_mov_tl(temp[0], tc1);
+                gen_addc(temp[1], c, tc1, tc2);
+                tcg_gen_mov_tl(temp[1], tc1);
+                gen_addc(temp[2], tc2, tc1, c);
+                tcg_gen_mov_tl(temp[2], tc1);
+                tcg_gen_add_tl(temp[3], temp[3], c);
+                /* Addition of p2 p1 p0 in 256 bit result */
+                gen_addc(temp[0], p0, tc1, c);
+                tcg_gen_mov_tl(temp[0], tc1);
+                gen_addc(temp[1], c, tc1, tc2);
+                tcg_gen_mov_tl(temp[1], tc1);
+                gen_addc(temp[2], tc2, tc1, c);
+                tcg_gen_mov_tl(temp[2], tc1);
+                tcg_gen_add_tl(temp[3], temp[3], c);
+
+                gen_addc(temp[1], p1, tc1, c);
+                tcg_gen_mov_tl(temp[1], tc1);
+                gen_addc(temp[2], c, tc1, tc2);
+                tcg_gen_mov_tl(temp[2], tc1);
+                tcg_gen_add_tl(temp[3], temp[3], tc2);
+
+                gen_addc(temp[2], p2, tc1, c);
+                tcg_gen_mov_tl(temp[2], tc1);
+                tcg_gen_add_tl(temp[3], temp[3], c);
+                /* final step */
+                tcg_gen_mov_tl(cpu_gpr[rd], temp[0]);
+                tcg_gen_mov_tl(p0, temp[1]);
+                tcg_gen_mov_tl(p1, temp[2]);
+                tcg_gen_mov_tl(p2, temp[3]);
+                tcg_temp_free(temp[0]);
+                tcg_temp_free(temp[1]);
+                tcg_temp_free(temp[2]);
+                tcg_temp_free(temp[3]);
+                tcg_temp_free(trs);
+                tcg_temp_free(trt);
+                tcg_temp_free(tc1);
+                tcg_temp_free(tc2);
+                tcg_temp_free(tc3);
+                tcg_temp_free(c);
+                opn = "v3mulu";
+                break;
+            }
+        }
+
+    } else {
+        generate_exception(ctx, EXCP_RI);
+    }
+}
+
+
+#endif
 /* Arithmetic */
 static void gen_arith (CPUState *env, DisasContext *ctx, uint32_t opc,
                        int rd, int rs, int rt)
 {
     const char *opn = "arith";

+    target_ulong mask = 0xFF;
     if (rd == 0 && opc != OPC_ADD && opc != OPC_SUB
        && opc != OPC_DADD && opc != OPC_DSUB) {
         /* If no destination, treat it as a NOP.
@@ -1637,6 +1887,22 @@ 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();
+            TCGv t2 = tcg_temp_new();
+            gen_load_gpr(t1, rs);
+            gen_load_gpr(t2, rt);
+            tcg_gen_andi_tl(t1, t1, mask);
+            tcg_gen_andi_tl(t2, t2, mask);
+            tcg_gen_add_tl(t0, t1, t2);
+            tcg_gen_andi_tl(t0, t0, mask);
+            gen_store_gpr(t0, rd);
+        }
+
+       opn = "baddu";
+       break;
     case OPC_SUB:
         {
             TCGv t0 = tcg_temp_local_new();
@@ -2013,7 +2279,74 @@ static void gen_HILO (DisasContext *ctx, uint32_t
opc, int reg)
     (void)opn; /* avoid a compiler warning */
     MIPS_DEBUG("%s %s", opn, regnames[reg]);
 }
+#if defined(TARGET_MIPS64)
+static void gen_seqsne (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();
+    switch (opc) {
+    case OPC_SEQ:
+        {
+            tcg_gen_xor_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]);
+            gen_load_gpr(t0, rd);
+            tcg_gen_setcondi_tl(TCG_COND_LTU, cpu_gpr[rd], t0, 1);
+        }
+        opn = "seq";
+        break;
+    case OPC_SNE:
+        {
+            tcg_gen_xor_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]);
+            gen_load_gpr(t0, rd);
+            gen_load_gpr(t1, 0);
+            tcg_gen_setcond_tl(TCG_COND_LTU, cpu_gpr[rd], t1, t0);
+        }
+        opn = "sne";
+        break;
+    default:
+        MIPS_INVAL(opn);
+        generate_exception(ctx, EXCP_RI);
+        goto out;
+    }
+out:
+        tcg_temp_free(t0);
+        tcg_temp_free(t1);

+}
+
+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_lw(temp, t0, ctx);
+        tcg_gen_add_tl(temp, temp, t1);
+        op_st_sw(temp, t0, ctx);
+        opn = "saa";
+        break;
+    case OPC_SAAD:
+        save_cpu_state(ctx, 0);
+        op_ld_ld(temp, t0, ctx);
+        tcg_gen_add_tl(temp, temp, t1);
+        op_st_sd(temp, t0, ctx);
+        opn = "saad";
+        break;
+    }
+
+    tcg_temp_free(t0);
+    tcg_temp_free(t1);
+}
+#endif
 static void gen_muldiv (DisasContext *ctx, uint32_t opc,
                         int rs, int rt)
 {
@@ -2149,6 +2482,10 @@ static void gen_muldiv (DisasContext *ctx, uint32_t
opc,
         gen_helper_dmult(t0, t1);
         opn = "dmult";
         break;
+    case OPC_DMUL:
+        gen_helper_dmult(t0, t1);
+        opn = "dmul";
+        break;
     case OPC_DMULTU:
         gen_helper_dmultu(t0, t1);
         opn = "dmultu";
@@ -2368,7 +2705,49 @@ static void gen_cl (DisasContext *ctx, uint32_t opc,
     MIPS_DEBUG("%s %s, %s", opn, regnames[rd], regnames[rs]);
     tcg_temp_free(t0);
 }
+#if defined(TARGET_MIPS64)
+static void insn_opc_pop (DisasContext *ctx, CPUState *env, uint32_t opc,
+                          int rd, int rs, int rt)
+{
+    TCGv num = tcg_temp_new();
+    TCGv res = tcg_temp_new();
+    target_ulong maskb = 1;
+    gen_load_gpr(num, rs);
+    TCGv ones=tcg_temp_new();
+    gen_load_gpr(ones, 0);
+    int x=1;
+    tcg_gen_andi_tl(res, num, maskb);
+    tcg_gen_add_tl(ones,ones, res);
+    while (x <= 31) {
+        tcg_gen_shri_i64(num, num, 1);
+        tcg_gen_andi_tl(res, num, maskb);
+        tcg_gen_add_tl(ones, ones, res);
+        x++;
+    }
+    gen_store_gpr(ones, rd);
+}
+static void insn_opc_dpop (DisasContext *ctx, CPUState *env, uint32_t opc,
+                           int rd, int rs, int rt)
+{
+    TCGv num, res, ones;
+    num = tcg_temp_new();
+    res = tcg_temp_new();
+    ones = tcg_temp_new();
+    target_ulong maskb = 1;
+    gen_load_gpr(num, rs);
+    int x = 1;
+    tcg_gen_andi_tl(res, num, maskb);
+    tcg_gen_mov_tl(ones, res);

+    while (x <= 63) {
+        tcg_gen_shri_i64(num, num, 1);
+        tcg_gen_andi_tl(res, num, maskb);
+        tcg_gen_add_tl(ones, ones, res);
+        x++;
+    }
+    gen_store_gpr(ones, rd);
+}
+#endif
 /* Godson integer instructions */
 static void gen_loongson_integer (DisasContext *ctx, uint32_t opc,
                                 int rd, int rs, int rt)
@@ -2705,6 +3084,7 @@ static void gen_compute_branch (DisasContext *ctx,
uint32_t opc,
     target_ulong btgt = -1;
     int blink = 0;
     int bcond_compute = 0;
+    target_ulong maskb; /* Used in BBIT0 and BBIT1*/
     TCGv t0 = tcg_temp_new();
     TCGv t1 = tcg_temp_new();

@@ -2730,6 +3110,39 @@ static void gen_compute_branch (DisasContext *ctx,
uint32_t opc,
         }
         btgt = ctx->pc + insn_bytes + offset;
         break;
+    case OPC_BBIT1:
+        gen_load_gpr(t0, rs);
+        gen_load_gpr(t1, 0);
+        maskb = 1ULL << rt;
+        tcg_gen_andi_tl(t0, t0, maskb);
+        bcond_compute = 1;
+        btgt = ctx->pc + insn_bytes + offset;
+        break;
+    case OPC_BBIT132:
+        gen_load_gpr(t0, rs);
+        gen_load_gpr(t1, 0);
+        maskb = 1ULL << (rt + 32);
+        tcg_gen_andi_tl(t0, t0, maskb);
+        bcond_compute = 1;
+        btgt = ctx->pc + insn_bytes + offset;
+        break;
+    case OPC_BBIT0:
+        gen_load_gpr(t0, rs);
+        gen_load_gpr(t1, 0);
+        maskb = 1ULL << rt;
+        tcg_gen_andi_tl(t0, t0, maskb);
+        bcond_compute = 1;
+        btgt = ctx->pc + insn_bytes + offset;
+        break;
+    case OPC_BBIT032:
+        gen_load_gpr(t0, rs);
+        gen_load_gpr(t1, 0);
+        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:
@@ -2888,6 +3301,18 @@ 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:
+            tcg_gen_setcond_tl(TCG_COND_NE, bcond, t0, t1);
+            goto not_likely;
+        case OPC_BBIT132:
+            tcg_gen_setcond_tl(TCG_COND_NE, bcond, t0, t1);
+            goto not_likely;
+            case OPC_BBIT0:
+            tcg_gen_setcond_tl(TCG_COND_EQ, bcond, t0, t1);
+            goto not_likely;
+        case OPC_BBIT032:
+            tcg_gen_setcond_tl(TCG_COND_EQ, bcond, t0, t1);
+            goto not_likely;
         case OPC_BNEL:
             tcg_gen_setcond_tl(TCG_COND_NE, bcond, t0, t1);
             MIPS_DEBUG("bnel %s, %s, " TARGET_FMT_lx,
@@ -2983,7 +3408,44 @@ static void gen_compute_branch (DisasContext *ctx,
uint32_t opc,
     tcg_temp_free(t0);
     tcg_temp_free(t1);
 }
+/*For cavium specific extract instructions*/
+#if defined(TARGET_MIPS64)
+static void gen_exts (CPUState *env,DisasContext *ctx, uint32_t opc, int
rt,
+                      int rs, int lsb, int msb)
+{
+    TCGv t0 = tcg_temp_new();
+    TCGv t1 = tcg_temp_new();
+    target_ulong mask;
+    gen_load_gpr(t1, rs);
+    switch (opc) {
+    case OPC_EXTS:
+        tcg_gen_shri_tl(t0, t1, lsb);
+        tcg_gen_andi_tl(t0, t0, (1ULL << (msb + 1)) - 1);
+        /* To sign extened the remaining bits according to
+           the msb of the bit field */
+        mask = 1ULL << msb;
+        tcg_gen_andi_tl(t1, t0, mask);
+        tcg_gen_addi_tl(t1, t1, -1);
+        tcg_gen_not_i64(t1, t1);
+        tcg_gen_or_tl(t0, t0, t1);
+        gen_store_gpr(t0, rt);
+        break;
+    case OPC_EXTS32:
+        tcg_gen_shri_tl(t0, t1, lsb + 32);
+        tcg_gen_andi_tl(t0, t0, (1ULL << (msb + 1)) - 1);
+        mask = 1ULL << msb;
+        tcg_gen_andi_tl(t1, t0, mask);
+        tcg_gen_addi_tl(t1, t1, -1);
+        tcg_gen_not_i64(t1, t1);
+        tcg_gen_or_tl(t0, t0, t1);
+        gen_store_gpr(t0, rt);
+        break;

+    }
+    tcg_temp_free(t0);
+    tcg_temp_free(t1);
+}
+#endif
 /* special3 bitfield operations */
 static void gen_bitops (DisasContext *ctx, uint32_t opc, int rt,
                         int rs, int lsb, int msb)
@@ -3063,6 +3525,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:
@@ -11605,7 +12083,7 @@ static void decode_opc (CPUState *env, DisasContext
*ctx, int *is_branch)
     int32_t offset;
     int rs, rt, rd, sa;
     uint32_t op, op1, op2;
-    int16_t imm;
+    int16_t imm, imm10;

     /* make sure instructions are on a word boundary */
     if (ctx->pc & 0x3) {
@@ -11634,6 +12112,9 @@ static void decode_opc (CPUState *env, DisasContext
*ctx, int *is_branch)
     rd = (ctx->opcode >> 11) & 0x1f;
     sa = (ctx->opcode >> 6) & 0x1f;
     imm = (int16_t)ctx->opcode;
+    /* 10 bit Immediate value For SEQI,SNEI */
+    imm10 = (ctx->opcode >> 6) & 0x3ff;
+
     switch (op) {
     case OPC_SPECIAL:
         op1 = MASK_SPECIAL(ctx->opcode);
@@ -11859,6 +12340,71 @@ 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_insn(env, ctx, ISA_MIPS3);
+            check_mips_64(ctx);
+            gen_muldiv(ctx, op1, rs, rt);
+            tcg_gen_mov_tl(cpu_gpr[rd], cpu_LO[0]);
+            break;
+        case OPC_CINS:
+            check_insn(env, ctx, ISA_MIPS64R2);
+            check_mips_64(ctx);
+            gen_bitops(ctx, op1, rt, rs, sa, rd);
+            break;
+        case OPC_CINS32:
+            check_mips_64(ctx);
+            gen_bitops(ctx, op1, rt, rs, sa, rd);
+            break;
+        case OPC_MTM0:
+            check_mips_64(ctx);
+            gen_LMI(env, ctx, op1, rs, rt, rd);
+            break;
+        case OPC_MTM1:
+            check_mips_64(ctx);
+            gen_LMI(env, ctx, op1, rs, rt, rd);
+            break;
+        case OPC_MTM2:
+            check_mips_64(ctx);
+            gen_LMI(env, ctx, op1, rs, rt, rd);
+            break;
+        case OPC_MTP0:
+            check_mips_64(ctx);
+            gen_LMI(env, ctx, op1, rs, rt, rd);
+            break;
+        case OPC_MTP1:
+            check_mips_64(ctx);
+            gen_LMI(env, ctx, op1, rs, rt, rd);
+            break;
+        case OPC_MTP2:
+            check_mips_64(ctx);
+            gen_LMI(env, ctx, op1, rs, rt, rd);
+            break;
+        case OPC_VMULU:
+            check_mips_64(ctx);
+            gen_LMI(env, ctx, op1, rs, rt, rd);
+            break;
+        case OPC_BADDU:
+            gen_arith(env, ctx, op1, rd, rs, rt);
+            break;
+        case OPC_EXTS:
+            check_mips_64(ctx);
+            gen_exts(env, ctx, op1, rt, rs, sa, rd);
+            break;
+        case OPC_EXTS32:
+            check_mips_64(ctx);
+            gen_exts(env, ctx, op1, rt, rs, sa, rd);
+            break;
+        case OPC_SAA:
+            gen_saa(env, ctx, op1, rt, rs);
+            break;
+        case OPC_SAAD:
+            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);
@@ -11878,13 +12424,24 @@ static void decode_opc (CPUState *env,
DisasContext *ctx, int *is_branch)
             break;
         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:
             check_insn(env, ctx, INSN_LOONGSON2F);
             gen_loongson_integer(ctx, op1, rd, rs, rt);
             break;
+        case OPC_MULT_G_2F:
+            if (!TARGET_OCTEON) {
+                check_insn(env, ctx, INSN_LOONGSON2F);
+                gen_loongson_integer(ctx, op1, rd, rs, rt);
+            } else {
+#if defined(TARGET_MIPS64)
+                /* Cavium Specific vmm0 */
+                check_mips_64(ctx);
+                gen_LMI(env, ctx, op1, rs, rt, rd);
+#endif
+            }
+            break;
 #if defined(TARGET_MIPS64)
         case OPC_DCLO:
         case OPC_DCLZ:
@@ -11892,7 +12449,6 @@ static void decode_opc (CPUState *env, DisasContext
*ctx, int *is_branch)
             check_mips_64(ctx);
             gen_cl(ctx, op1, rd, rs);
             break;
-        case OPC_DMULT_G_2F:
         case OPC_DMULTU_G_2F:
         case OPC_DDIV_G_2F:
         case OPC_DDIVU_G_2F:
@@ -11901,6 +12457,39 @@ 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_DMULT_G_2F:
+            if (!TARGET_OCTEON) {
+                check_insn(env, ctx, INSN_LOONGSON2F);
+                gen_loongson_integer(ctx, op1, rd, rs, rt);
+            } else {
+                /* Cavium Specific instruction v3mulu */
+                check_mips_64(ctx);
+                gen_LMI(env, ctx, op1, rs, rt, rd);
+            }
+            break;
+        case OPC_SEQ:
+            check_mips_64(ctx);
+            gen_seqsne(ctx, op1, rd, rs, rt);
+            break;
+        case OPC_SNE:
+            check_mips_64(ctx);
+            gen_seqsne(ctx, op1, rd, rs, rt);
+            break;
+        case OPC_SEQI:
+            check_mips_64(ctx);
+            gen_set_imm(env, op1, rt, rs, imm10);
+            break;
+        case OPC_SNEI:
+            check_mips_64(ctx);
+            gen_set_imm(env, op1, rt, rs, imm10);
+            break;
+        case OPC_POP:
+            insn_opc_pop(ctx, env, op1, rd, rs, rt);
+            break;
+        case OPC_DPOP:
+            check_mips_64(ctx);
+            insn_opc_dpop(ctx, env, op1, rd, rs, rt);
+            break;
 #endif
         default:            /* Invalid */
             MIPS_INVAL("special2");
@@ -12192,10 +12781,32 @@ 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 TARGET_OCTEON is set these opcodes will belong to Cavium */
+    case OPC_LWC2: /*BBIT0*/
+        if(TARGET_OCTEON) {
+            gen_compute_branch(ctx, op, 4, rs, rt, imm << 2);
+            *is_branch = 1;
+            break;
+        }
+    case OPC_LDC2: /*BBIT032*/
+        if(TARGET_OCTEON) {
+            gen_compute_branch(ctx, op, 4, rs, rt, imm << 2);
+            *is_branch = 1;
+            break;
+        }
+    case OPC_SWC2: /*BBIT1*/
+        if(TARGET_OCTEON) {
+            gen_compute_branch(ctx, op, 4, rs, rt, imm << 2);
+            *is_branch = 1;
+            break;
+        }
+    case OPC_SDC2: /*BBIT132*/
+        if(TARGET_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);
@@ -12584,6 +13195,18 @@ static void mips_tcg_init(void)
     cpu_dspctrl = tcg_global_mem_new(TCG_AREG0,
                                      offsetof(CPUState,
active_tc.DSPControl),
                                      "DSPControl");
+    mpl0 = tcg_global_mem_new(TCG_AREG0,
+                              offsetof(CPUState, Reg.MPL0), "MPL0");
+    mpl1 = tcg_global_mem_new(TCG_AREG0,
+                              offsetof(CPUState, Reg.MPL1), "MPL1");
+    mpl2 = tcg_global_mem_new(TCG_AREG0,
+                              offsetof(CPUState, Reg.MPL2), "MPL2");
+    p0 = tcg_global_mem_new(TCG_AREG0,
+                            offsetof(CPUState, Reg.P0), "P0");
+    p1 = tcg_global_mem_new(TCG_AREG0,
+                            offsetof(CPUState, Reg.P1), "P1");
+    p2 = tcg_global_mem_new(TCG_AREG0,
+                            offsetof(CPUState, Reg.P2), "P2");
     bcond = tcg_global_mem_new(TCG_AREG0,
                                offsetof(CPUState, bcond), "bcond");
     btarget = tcg_global_mem_new(TCG_AREG0,
@@ -12607,6 +13230,18 @@ static void mips_tcg_init(void)

 #include "translate_init.c"

+#if defined(TARGET_MIPS64)
+
+static void set_cvmctl_register(CPUMIPSState *env)
+{
+    env->CvmCtlRegister.cvmctl = env->CvmCtlRegister.cvmctl
+                                 ^ env->CvmCtlRegister.cvmctl;
+    env->CvmCtlRegister.cvmctl =
FUSE_START_BIT(env->CvmCtlRegister.cvmctl);
+    env->CvmCtlRegister.cvmctl = KASUMI(env->CvmCtlRegister.cvmctl);
+    env->CvmCtlRegister.cvmctl = IPPCI(env->CvmCtlRegister.cvmctl);
+    env->CvmCtlRegister.cvmctl = IPTI(env->CvmCtlRegister.cvmctl);
+}
+#endif
 CPUMIPSState *cpu_mips_init (const char *cpu_model)
 {
     CPUMIPSState *env;
@@ -12619,6 +13254,10 @@ CPUMIPSState *cpu_mips_init (const char *cpu_model)
     env->cpu_model = def;
     env->cpu_model_str = cpu_model;

+#if defined(TARGET_MIPS64)
+    /*Function for setting cvmctl register*/
+    set_cvmctl_register(env);
+#endif
     cpu_exec_init(env);
 #ifndef CONFIG_USER_ONLY
     mmu_init(env, def);

Comments

Riku Voipio March 29, 2011, 8:55 a.m. UTC | #1
Hi,

First, do you have some instructions on howto build Octeon usermode
64bit binaries. Second, I think we would prefer that the patch was split
to smaller patches. At least the target-mips changes should be a separate
patch.

Some more comments included inline between the code.

On Sat, Mar 26, 2011 at 11:58:37AM +0500, Khansa Butt wrote:
> >From cd88be1263d0fc9802cd4dd358ed0299c0d106b0 Mon Sep 17 00:00:00 2001
> From: Khansa Butt & Ehsan-ul-Haq <khansa@kics.edu.pk>
> Date: Sat, 26 Mar 2011 11:53:11 +0500
> Subject: [PATCH] MIPS64 user mode emulation in QEMU
>  This patch adds support for Cavium Network's
>  Octeon 57XX user mode instructions.  Octeon
>  57xx is based on MIPS64.  So this patch is
>  the first MIPS64 User Mode Emulation in QEMU
>  This is the team(Khansa Butt, Ehsan-ul-Haq, Abdul Qadeer, Abdul Waheed)
>  work of HPCNL Lab at KICS-UET Lahore.
> 
> 
> Signed-off-by: Khansa Butt <khansa@kics.edu.pk>
> ---
>  configure                             |    1 +
>  default-configs/mips64-linux-user.mak |    1 +
>  exec.c                                |    1 +
>  linux-user/elfload.c                  |   15 +-
>  linux-user/main.c                     |   20 +-
>  linux-user/mips64/syscall.h           |    2 +
>  linux-user/signal.c                   |    3 +-
>  linux-user/syscall.c                  |    2 +
>  target-mips/cpu.h                     |   16 +
>  target-mips/translate.c               |  659
> ++++++++++++++++++++++++++++++++-
>  10 files changed, 704 insertions(+), 16 deletions(-)
>  create mode 100644 default-configs/mips64-linux-user.mak
> 
> diff --git a/configure b/configure
> index 438219b..045a4ef 100755
> --- a/configure
> +++ b/configure
> @@ -1011,6 +1011,7 @@ cris-linux-user \
>  m68k-linux-user \
>  microblaze-linux-user \
>  mips-linux-user \
> +mips64-linux-user \
>  mipsel-linux-user \
>  ppc-linux-user \
>  ppc64-linux-user \
> diff --git a/default-configs/mips64-linux-user.mak
> b/default-configs/mips64-linux-user.mak
> new file mode 100644
> index 0000000..1598bfc
> --- /dev/null
> +++ b/default-configs/mips64-linux-user.mak
> @@ -0,0 +1 @@
> +# Default configuration for mips64-linux-user
> diff --git a/exec.c b/exec.c
> index 49c28b1..ee3f78e 100644
> --- a/exec.c
> +++ b/exec.c
> @@ -2441,6 +2441,7 @@ int page_check_range(target_ulong start, target_ulong
> len, int flags)
>      for (addr = start, len = end - start;
>           len != 0;
>           len -= TARGET_PAGE_SIZE, addr += TARGET_PAGE_SIZE) {
> +        addr  &= qemu_host_page_mask;
>          p = page_find(addr >> TARGET_PAGE_BITS);

Are you sure this will not generate ill effect on other target/host architecture
combinations?

>          if( !p )
>              return -1;
> diff --git a/linux-user/elfload.c b/linux-user/elfload.c
> index 33d776d..60fe85e 100644
> --- a/linux-user/elfload.c
> +++ b/linux-user/elfload.c
> @@ -16,6 +16,8 @@
>  #include "qemu.h"
>  #include "disas.h"
> 
> +extern int TARGET_OCTEON;
> +
>  #ifdef _ARCH_PPC64
>  #undef ARCH_DLINFO
>  #undef ELF_PLATFORM
> @@ -25,6 +27,9 @@
>  #undef ELF_ARCH
>  #endif
> 
> +#define EF_MIPS_MARCH 16711680
> +#define E_MIPS_MACH_OCTEON 9109504
> +

please use hexadecimal values.

>  #define ELF_OSABI   ELFOSABI_SYSV
> 
>  /* from personality.h */
> @@ -1313,7 +1318,7 @@ static void load_elf_image(const char *image_name, int
> image_fd,
>              vaddr_po = TARGET_ELF_PAGEOFFSET(vaddr);
>              vaddr_ps = TARGET_ELF_PAGESTART(vaddr);
> 
> -            error = target_mmap(vaddr_ps, eppnt->p_filesz + vaddr_po,
> +            error = target_mmap(vaddr_ps, eppnt->p_memsz + vaddr_po,
>                                  elf_prot, MAP_PRIVATE | MAP_FIXED,
>                                  image_fd, eppnt->p_offset - vaddr_po);
>              if (error == -1) {
> @@ -1588,7 +1593,13 @@ int load_elf_binary(struct linux_binprm * bprm,
> struct target_pt_regs * regs,
>         If we do nothing, we'll have overwritten this when we re-use
> bprm->buf
>         when we load the interpreter.  */
>      elf_ex = *(struct elfhdr *)bprm->buf;
> -
> +#if defined(TARGET_MIPS64)
> +    if ((elf_ex.e_flags & EF_MIPS_MARCH) == E_MIPS_MACH_OCTEON) {
> +        TARGET_OCTEON = 1;
> +    } else {
> +        TARGET_OCTEON = 0;
> +    }
> +#endif
>      bprm->p = copy_elf_strings(1, &bprm->filename, bprm->page, bprm->p);
>      bprm->p = copy_elf_strings(bprm->envc,bprm->envp,bprm->page,bprm->p);
>      bprm->p = copy_elf_strings(bprm->argc,bprm->argv,bprm->page,bprm->p);
> diff --git a/linux-user/main.c b/linux-user/main.c
> index 0d627d6..8b4b90b 100644
> --- a/linux-user/main.c
> +++ b/linux-user/main.c
> @@ -1937,10 +1937,16 @@ static int do_store_exclusive(CPUMIPSState *env)
>      int d;
> 
>      addr = env->lladdr;
> +    /* 64 bit address is converted to 32 bit value so that a valid
> +    * l1_map value can be accessed. This thing is needed for target
> +    * mips64 and host 32 bit x86
> +    */
> +    addr &= qemu_host_page_mask;

same as earlier.

>      page_addr = addr & TARGET_PAGE_MASK;
>      start_exclusive();
>      mmap_lock();
>      flags = page_get_flags(page_addr);
> +    addr = env->lladdr;
>      if ((flags & PAGE_READ) == 0) {
>          segv = 1;
>      } else {
> @@ -1978,7 +1984,8 @@ static int do_store_exclusive(CPUMIPSState *env)
>  void cpu_loop(CPUMIPSState *env)
>  {
>      target_siginfo_t info;
> -    int trapnr, ret;
> +    int trapnr;
> +    abi_long ret;
>      unsigned int syscall_num;
> 
>      for(;;) {
> @@ -1987,7 +1994,11 @@ void cpu_loop(CPUMIPSState *env)
>          cpu_exec_end(env);
>          switch(trapnr) {
>          case EXCP_SYSCALL:
> +#if defined(TARGET_MIPS64)
> +            syscall_num = env->active_tc.gpr[2] - 5000;
> +#else
>              syscall_num = env->active_tc.gpr[2] - 4000;
> +#endif
>              env->active_tc.PC += 4;
>              if (syscall_num >= sizeof(mips_syscall_args)) {
>                  ret = -ENOSYS;
> @@ -2013,7 +2024,8 @@ void cpu_loop(CPUMIPSState *env)
>                                   env->active_tc.gpr[5],
>                                   env->active_tc.gpr[6],
>                                   env->active_tc.gpr[7],
> -                                 arg5, arg6/*, arg7, arg8*/);
> +                                 env->active_tc.gpr[8],
> +                                 env->active_tc.gpr[9]/*, arg7, arg8*/);
>              }
>              if (ret == -TARGET_QEMU_ESIGRETURN) {
>                  /* Returning from a successful sigreturn syscall.
> @@ -2926,7 +2938,9 @@ int main(int argc, char **argv, char **envp)
>  #endif
>  #elif defined(TARGET_MIPS)
>  #if defined(TARGET_ABI_MIPSN32) || defined(TARGET_ABI_MIPSN64)
> -        cpu_model = "20Kc";
> +        /* we use this model so that we can decode MIPS64r2
> +           reserved instruction */
> +        cpu_model = "MIPS64R2-generic";
>  #else
>          cpu_model = "24Kf";
>  #endif
> diff --git a/linux-user/mips64/syscall.h b/linux-user/mips64/syscall.h
> index 668a2b9..1395e61 100644
> --- a/linux-user/mips64/syscall.h
> +++ b/linux-user/mips64/syscall.h
> @@ -217,5 +217,7 @@ struct target_pt_regs {
>  #define TARGET_ENOTRECOVERABLE 166     /* State not recoverable */
> 
> 
> +/* Nasty hack: define a fake errno value for use by sigreturn.  */
> +#define TARGET_QEMU_ESIGRETURN 255
> 
>  #define UNAME_MACHINE "mips64"
> diff --git a/linux-user/signal.c b/linux-user/signal.c
> index c846b8c..114116c 100644
> --- a/linux-user/signal.c
> +++ b/linux-user/signal.c
> @@ -2410,7 +2410,8 @@ void sparc64_get_context(CPUSPARCState *env)
>  #endif
>  #elif defined(TARGET_ABI_MIPSN64)
> 
> -# warning signal handling not implemented
> +/*this line is commented out to avoid compile time error*/
> +/*# warning signal handling not implemented*/
> 
>  static void setup_frame(int sig, struct target_sigaction *ka,
>   target_sigset_t *set, CPUState *env)
> diff --git a/linux-user/syscall.c b/linux-user/syscall.c
> index 499c4d7..47fef05 100644
> --- a/linux-user/syscall.c
> +++ b/linux-user/syscall.c
> @@ -7195,6 +7195,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long
> arg1,
>      case TARGET_NR_set_thread_area:
>  #if defined(TARGET_MIPS)
>        ((CPUMIPSState *) cpu_env)->tls_value = arg1;
> +       /*tls entry is moved to k0 so that this can be used later*/
> +      ((CPUMIPSState *) cpu_env)->active_tc.gpr[26] = arg1;

Does this affect the non-octeon mips ?

>        ret = 0;
>        break;
>  #elif defined(TARGET_CRIS)

And someone else will need to comment the TCG changes.

> diff --git a/target-mips/cpu.h b/target-mips/cpu.h
> index 2419aa9..59bcc0f 100644
> --- a/target-mips/cpu.h
> +++ b/target-mips/cpu.h
> @@ -140,6 +140,20 @@ typedef struct mips_def_t mips_def_t;
>  #define MIPS_FPU_MAX 1
>  #define MIPS_DSP_ACC 4
> 
> +typedef struct cavium_mul cavium_mul;
> +struct cavium_mul {
> + target_ulong MPL0;
> + target_ulong MPL1;
> + target_ulong MPL2;
> + target_ulong P0;
> + target_ulong P1;
> + target_ulong P2;
> +};
> +typedef struct cvmctl_register cvmctl_register;
> +struct cvmctl_register {
> + target_ulong cvmctl;
> +};
> +
>  typedef struct TCState TCState;
>  struct TCState {
>      target_ulong gpr[32];
> @@ -178,6 +192,8 @@ struct CPUMIPSState {
>      TCState active_tc;
>      CPUMIPSFPUContext active_fpu;
> 
> +    cavium_mul Reg;
> +    cvmctl_register CvmCtlRegister;
>      uint32_t current_tc;
>      uint32_t current_fpu;
> 
> diff --git a/target-mips/translate.c b/target-mips/translate.c
> index cce77be..9c3d772 100644
> --- a/target-mips/translate.c
> +++ b/target-mips/translate.c
> @@ -36,6 +36,15 @@
>  #define GEN_HELPER 1
>  #include "helper.h"
> 
> +int TARGET_OCTEON;
> +#if defined(TARGET_MIPS64)
> +/*Macros for setting values of cvmctl registers*/
> +#define FUSE_START_BIT(cvmctl)(cvmctl | 0x80000000)
> +#define KASUMI(cvmctl)(cvmctl | 0x20000000)
> +#define IPPCI(cvmctl)(cvmctl | 0x380)
> +#define IPTI(cvmctl)(cvmctl | 0x70)
> +#endif
> +
>  //#define MIPS_DEBUG_DISAS
>  //#define MIPS_DEBUG_SIGN_EXTENSIONS
> 
> @@ -70,6 +79,11 @@ enum {
>      OPC_JAL      = (0x03 << 26),
>      OPC_JALS     = OPC_JAL | 0x5,
>      OPC_BEQ      = (0x04 << 26),  /* Unconditional if rs = rt = 0 (B) */
> +    /* Cavium Specific */
> +    OPC_BBIT1    = (0x3a << 26),  /*jump on bit set, cavium specific*/
> +    OPC_BBIT132  = (0x3e << 26),  /*jump on bit set(one of the upper 32
> bits)*/
> +    OPC_BBIT0    = (0x32 << 26),  /*jump on bit clear, cavium specific*/
> +    OPC_BBIT032  = (0x36 << 26),  /*jump on bit set(one of the upper 32
> bits)*/
>      OPC_BEQL     = (0x14 << 26),
>      OPC_BNE      = (0x05 << 26),
>      OPC_BNEL     = (0x15 << 26),
> @@ -265,6 +279,31 @@ enum {
>      OPC_MADD     = 0x00 | OPC_SPECIAL2,
>      OPC_MADDU    = 0x01 | OPC_SPECIAL2,
>      OPC_MUL      = 0x02 | 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,
> +/**************************************/
>      OPC_MSUB     = 0x04 | OPC_SPECIAL2,
>      OPC_MSUBU    = 0x05 | OPC_SPECIAL2,
>      /* Loongson 2F */
> @@ -483,7 +522,7 @@ enum {
>  static TCGv_ptr cpu_env;
>  static TCGv cpu_gpr[32], cpu_PC;
>  static TCGv cpu_HI[MIPS_DSP_ACC], cpu_LO[MIPS_DSP_ACC],
> cpu_ACX[MIPS_DSP_ACC];
> -static TCGv cpu_dspctrl, btarget, bcond;
> +static TCGv cpu_dspctrl, btarget, bcond, mpl0, mpl1, mpl2, p0, p1, p2;
>  static TCGv_i32 hflags;
>  static TCGv_i32 fpu_fcr0, fpu_fcr31;
> 
> @@ -779,7 +818,9 @@ static inline void gen_op_addr_add (DisasContext *ctx,
> TCGv ret, TCGv arg0, TCGv
>         See the MIPS64 PRA manual, section 4.10. */
>      if (((ctx->hflags & MIPS_HFLAG_KSU) == MIPS_HFLAG_UM) &&
>          !(ctx->hflags & MIPS_HFLAG_UX)) {
> -        tcg_gen_ext32s_i64(ret, ret);
> +        /*This function sign extend 32 bit value to 64 bit, was causing
> error
> +          when ld instruction came.Thats why it is commmented out*/
> +       /* tcg_gen_ext32s_i64(ret, ret);*/
>      }
>  #endif
>  }
> @@ -1419,7 +1460,33 @@ static void gen_arith_imm (CPUState *env,
> DisasContext *ctx, uint32_t opc,
>      (void)opn; /* avoid a compiler warning */
>      MIPS_DEBUG("%s %s, %s, " TARGET_FMT_lx, opn, regnames[rt],
> regnames[rs], uimm);
>  }
> -
> +#if defined(TARGET_MIPS64)
> +/*set on equal immidiate/seton not equal immidiate*/
> +static void gen_set_imm(CPUState *env, uint32_t opc, int rt, int rs,
> int16_t imm)
> +{
> +    target_ulong uimm;
> +    TCGv t0, t1;
> +    const char *opn = "imm set";
> +    uimm = (uint16_t)imm;
> +    t0 = tcg_temp_new();
> +    t1 = tcg_temp_new();
> +    switch (opc) {
> +    case OPC_SEQI:
> +        tcg_gen_xori_tl(cpu_gpr[rt], cpu_gpr[rs], uimm);
> +        gen_load_gpr(t0, rt);
> +        tcg_gen_setcondi_tl(TCG_COND_LTU, cpu_gpr[rt], t0, 1);
> +        opn = "seqi";
> +        break;
> +    case OPC_SNEI:
> +        tcg_gen_xori_tl(cpu_gpr[rt], cpu_gpr[rs], uimm);
> +        gen_load_gpr(t0, rt);
> +        gen_load_gpr(t1, 0);
> +        tcg_gen_setcond_tl(TCG_COND_LTU, cpu_gpr[rt], t1, t0);
> +        opn = "snei";
> +        break;
> +    }
> +}
> +#endif
>  /* Logic with immediate operand */
>  static void gen_logic_imm (CPUState *env, uint32_t opc, int rt, int rs,
> int16_t imm)
>  {
> @@ -1583,13 +1650,196 @@ static void gen_shift_imm(CPUState *env,
> DisasContext *ctx, uint32_t opc,
>      MIPS_DEBUG("%s %s, %s, " TARGET_FMT_lx, opn, regnames[rt],
> regnames[rs], uimm);
>      tcg_temp_free(t0);
>  }
> +#if defined(TARGET_MIPS64)
> +/* Addition and carry detection*/
> +static void gen_addc (TCGv arg1, TCGv arg2, TCGv res, TCGv c)
> +{
> +    tcg_gen_add_tl(res, arg1, arg2);
> +    tcg_gen_setcond_tl(TCG_COND_LTU, c, res, arg1);
> +}
> +static void gen_LMI (CPUMIPSState *env, DisasContext *ctx, uint32_t opc,
> +                 int rs, int rt, int rd)
> +{
> +    const char *opn = "LMI";
> +    TCGv t0, t1;
> +    int nomul = env->CvmCtlRegister.cvmctl & 0x8000000;
> +    if (!nomul) {
> +        switch (opc) {
> +        case OPC_MTM0:
> +            tcg_gen_mov_tl(mpl0, cpu_gpr[rs]);
> +            tcg_gen_movi_tl(p0, 0);
> +            tcg_gen_movi_tl(p1, 0);
> +            tcg_gen_movi_tl(p2, 0);
> +            opn = "mtm0";
> +            break;
> +        case OPC_MTM1:
> +            tcg_gen_mov_tl(mpl1, cpu_gpr[rs]);
> +            tcg_gen_movi_tl(p0, 0);
> +            tcg_gen_movi_tl(p1, 0);
> +            tcg_gen_movi_tl(p2, 0);
> +            opn = "mtm1";
> +            break;
> +        case OPC_MTM2:
> +            tcg_gen_mov_tl(mpl2, cpu_gpr[rs]);
> +            tcg_gen_movi_tl(p0, 0);
> +            tcg_gen_movi_tl(p1, 0);
> +            tcg_gen_movi_tl(p2, 0);
> +            opn = "mtm2";
> +            break;
> +        case OPC_MTP0:
> +            tcg_gen_mov_tl(p0, cpu_gpr[rs]);
> +            opn = "mtp0";
> +            break;
> +        case OPC_MTP1:
> +            tcg_gen_mov_tl(p1, cpu_gpr[rs]);
> +            opn = "mtp1";
> +            break;
> +        case OPC_MTP2:
> +            tcg_gen_mov_tl(p2, cpu_gpr[rs]);
> +            opn = "mtp2";
> +            break;
> +        case OPC_VMM0:
> +            t0 = tcg_temp_new();
> +            t1 = tcg_temp_new();
> +            gen_load_gpr(t1, rs);
> +            gen_helper_dmultu(t1, mpl0);
> +            gen_load_gpr(t0, rt);
> +            tcg_gen_add_tl(t0, t0, cpu_LO[0]);
> +            tcg_gen_add_tl(t0, t0, p0);
> +            gen_store_gpr(t0, rd);
> +            tcg_gen_mov_tl(mpl0, cpu_gpr[rd]);
> +            tcg_gen_movi_tl(p0, 0);
> +            tcg_gen_movi_tl(p1, 0);
> +            tcg_gen_movi_tl(p2, 0);
> +            tcg_temp_free(t0);
> +            tcg_temp_free(t1);
> +            opn = "vmm0";
> +            break;
> +        case OPC_VMULU:
> +            {
> +                TCGv t2, c;
> +                t0 = tcg_temp_new();
> +                t1 = tcg_temp_new();
> +                t2 = tcg_temp_new();
> +                c = tcg_temp_new();
> +                gen_load_gpr(t1, rs);
> +                gen_load_gpr(t2, rt);
> +                gen_helper_dmultu(t1, mpl0);
> +                tcg_gen_mov_tl(t0, cpu_LO[0]);
> +                /*if carry comes due to addition of rt and LO register,
> +                 * this carry should be added to HI register.
> +                 */
> +                gen_addc(t0, t2, t1, c);
> 
> +                tcg_gen_add_tl(cpu_HI[0], cpu_HI[0], c);
> +                /* t0 = t1 + p0 where t1 = LO+rt*/
> +                gen_addc(t1, p0, t0, c);
> +                tcg_gen_add_tl(cpu_HI[0], cpu_HI[0], c);
> +
> +                tcg_gen_mov_tl(cpu_gpr[rd], t0);
> +                tcg_gen_mov_tl(p0, cpu_HI[0]);
> +                tcg_temp_free(t0);
> +                tcg_temp_free(t1);
> +                tcg_temp_free(t2);
> +                opn = "vmulu";
> +                break;
> +            }
> +        case OPC_V3MULU:
> +            {
> +                TCGv temp[4];
> +                TCGv c;
> +                TCGv trs, trt, tc1, tc2, tc3;
> +                temp[0] = tcg_temp_new();
> +                temp[1] = tcg_temp_new();
> +                temp[2] = tcg_temp_new();
> +                temp[3] = tcg_temp_new();
> +                trs = tcg_temp_new();
> +                trt = tcg_temp_new();
> +                tc1 = tcg_temp_new();
> +                tc2 = tcg_temp_new();
> +                tc3 = tcg_temp_new();
> +                c = tcg_temp_new();
> +                gen_load_gpr(trs, rs);
> +                gen_load_gpr(trt, rt);
> +                /* rs × (MPL2 || MPL1 || MPL0) (192X64 bit multiplication)
> */
> +                gen_helper_dmultu(trs, mpl0);
> +                tcg_gen_mov_tl(temp[0], cpu_LO[0]);
> +                tcg_gen_mov_tl(temp[1], cpu_HI[0]);
> +
> +                gen_helper_dmultu(trs, mpl1);
> +                tcg_gen_mov_tl(temp[2], cpu_HI[0]);
> +                gen_addc(cpu_LO[0], temp[1], tc1, tc2);
> +                gen_addc(temp[2], tc2, tc3, c);
> +                tcg_gen_mov_tl(temp[1], tc1);
> +                tcg_gen_mov_tl(temp[2], tc3);
> +                tcg_gen_mov_tl(temp[3], c);
> +
> +                gen_helper_dmultu(trs, mpl2);
> +                tcg_gen_add_tl(temp[3], temp[3], cpu_HI[0]);
> +                gen_addc(cpu_LO[0], temp[2], tc1, tc2);
> +                tcg_gen_mov_tl(temp[2], tc1);
> +                tcg_gen_add_tl(temp[3], temp[3], tc2);
> +                /* Addition of rt in 256 bit result
> +                  (t3 t2 t1 t0 contain result) */
> +                gen_addc(temp[0], trt, tc1, c);
> +                tcg_gen_mov_tl(temp[0], tc1);
> +                gen_addc(temp[1], c, tc1, tc2);
> +                tcg_gen_mov_tl(temp[1], tc1);
> +                gen_addc(temp[2], tc2, tc1, c);
> +                tcg_gen_mov_tl(temp[2], tc1);
> +                tcg_gen_add_tl(temp[3], temp[3], c);
> +                /* Addition of p2 p1 p0 in 256 bit result */
> +                gen_addc(temp[0], p0, tc1, c);
> +                tcg_gen_mov_tl(temp[0], tc1);
> +                gen_addc(temp[1], c, tc1, tc2);
> +                tcg_gen_mov_tl(temp[1], tc1);
> +                gen_addc(temp[2], tc2, tc1, c);
> +                tcg_gen_mov_tl(temp[2], tc1);
> +                tcg_gen_add_tl(temp[3], temp[3], c);
> +
> +                gen_addc(temp[1], p1, tc1, c);
> +                tcg_gen_mov_tl(temp[1], tc1);
> +                gen_addc(temp[2], c, tc1, tc2);
> +                tcg_gen_mov_tl(temp[2], tc1);
> +                tcg_gen_add_tl(temp[3], temp[3], tc2);
> +
> +                gen_addc(temp[2], p2, tc1, c);
> +                tcg_gen_mov_tl(temp[2], tc1);
> +                tcg_gen_add_tl(temp[3], temp[3], c);
> +                /* final step */
> +                tcg_gen_mov_tl(cpu_gpr[rd], temp[0]);
> +                tcg_gen_mov_tl(p0, temp[1]);
> +                tcg_gen_mov_tl(p1, temp[2]);
> +                tcg_gen_mov_tl(p2, temp[3]);
> +                tcg_temp_free(temp[0]);
> +                tcg_temp_free(temp[1]);
> +                tcg_temp_free(temp[2]);
> +                tcg_temp_free(temp[3]);
> +                tcg_temp_free(trs);
> +                tcg_temp_free(trt);
> +                tcg_temp_free(tc1);
> +                tcg_temp_free(tc2);
> +                tcg_temp_free(tc3);
> +                tcg_temp_free(c);
> +                opn = "v3mulu";
> +                break;
> +            }
> +        }
> +
> +    } else {
> +        generate_exception(ctx, EXCP_RI);
> +    }
> +}
> +
> +
> +#endif
>  /* Arithmetic */
>  static void gen_arith (CPUState *env, DisasContext *ctx, uint32_t opc,
>                         int rd, int rs, int rt)
>  {
>      const char *opn = "arith";
> 
> +    target_ulong mask = 0xFF;
>      if (rd == 0 && opc != OPC_ADD && opc != OPC_SUB
>         && opc != OPC_DADD && opc != OPC_DSUB) {
>          /* If no destination, treat it as a NOP.
> @@ -1637,6 +1887,22 @@ 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();
> +            TCGv t2 = tcg_temp_new();
> +            gen_load_gpr(t1, rs);
> +            gen_load_gpr(t2, rt);
> +            tcg_gen_andi_tl(t1, t1, mask);
> +            tcg_gen_andi_tl(t2, t2, mask);
> +            tcg_gen_add_tl(t0, t1, t2);
> +            tcg_gen_andi_tl(t0, t0, mask);
> +            gen_store_gpr(t0, rd);
> +        }
> +
> +       opn = "baddu";
> +       break;
>      case OPC_SUB:
>          {
>              TCGv t0 = tcg_temp_local_new();
> @@ -2013,7 +2279,74 @@ static void gen_HILO (DisasContext *ctx, uint32_t
> opc, int reg)
>      (void)opn; /* avoid a compiler warning */
>      MIPS_DEBUG("%s %s", opn, regnames[reg]);
>  }
> +#if defined(TARGET_MIPS64)
> +static void gen_seqsne (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();
> +    switch (opc) {
> +    case OPC_SEQ:
> +        {
> +            tcg_gen_xor_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]);
> +            gen_load_gpr(t0, rd);
> +            tcg_gen_setcondi_tl(TCG_COND_LTU, cpu_gpr[rd], t0, 1);
> +        }
> +        opn = "seq";
> +        break;
> +    case OPC_SNE:
> +        {
> +            tcg_gen_xor_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]);
> +            gen_load_gpr(t0, rd);
> +            gen_load_gpr(t1, 0);
> +            tcg_gen_setcond_tl(TCG_COND_LTU, cpu_gpr[rd], t1, t0);
> +        }
> +        opn = "sne";
> +        break;
> +    default:
> +        MIPS_INVAL(opn);
> +        generate_exception(ctx, EXCP_RI);
> +        goto out;
> +    }
> +out:
> +        tcg_temp_free(t0);
> +        tcg_temp_free(t1);
> 
> +}
> +
> +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_lw(temp, t0, ctx);
> +        tcg_gen_add_tl(temp, temp, t1);
> +        op_st_sw(temp, t0, ctx);
> +        opn = "saa";
> +        break;
> +    case OPC_SAAD:
> +        save_cpu_state(ctx, 0);
> +        op_ld_ld(temp, t0, ctx);
> +        tcg_gen_add_tl(temp, temp, t1);
> +        op_st_sd(temp, t0, ctx);
> +        opn = "saad";
> +        break;
> +    }
> +
> +    tcg_temp_free(t0);
> +    tcg_temp_free(t1);
> +}
> +#endif
>  static void gen_muldiv (DisasContext *ctx, uint32_t opc,
>                          int rs, int rt)
>  {
> @@ -2149,6 +2482,10 @@ static void gen_muldiv (DisasContext *ctx, uint32_t
> opc,
>          gen_helper_dmult(t0, t1);
>          opn = "dmult";
>          break;
> +    case OPC_DMUL:
> +        gen_helper_dmult(t0, t1);
> +        opn = "dmul";
> +        break;
>      case OPC_DMULTU:
>          gen_helper_dmultu(t0, t1);
>          opn = "dmultu";
> @@ -2368,7 +2705,49 @@ static void gen_cl (DisasContext *ctx, uint32_t opc,
>      MIPS_DEBUG("%s %s, %s", opn, regnames[rd], regnames[rs]);
>      tcg_temp_free(t0);
>  }
> +#if defined(TARGET_MIPS64)
> +static void insn_opc_pop (DisasContext *ctx, CPUState *env, uint32_t opc,
> +                          int rd, int rs, int rt)
> +{
> +    TCGv num = tcg_temp_new();
> +    TCGv res = tcg_temp_new();
> +    target_ulong maskb = 1;
> +    gen_load_gpr(num, rs);
> +    TCGv ones=tcg_temp_new();
> +    gen_load_gpr(ones, 0);
> +    int x=1;
> +    tcg_gen_andi_tl(res, num, maskb);
> +    tcg_gen_add_tl(ones,ones, res);
> +    while (x <= 31) {
> +        tcg_gen_shri_i64(num, num, 1);
> +        tcg_gen_andi_tl(res, num, maskb);
> +        tcg_gen_add_tl(ones, ones, res);
> +        x++;
> +    }
> +    gen_store_gpr(ones, rd);
> +}
> +static void insn_opc_dpop (DisasContext *ctx, CPUState *env, uint32_t opc,
> +                           int rd, int rs, int rt)
> +{
> +    TCGv num, res, ones;
> +    num = tcg_temp_new();
> +    res = tcg_temp_new();
> +    ones = tcg_temp_new();
> +    target_ulong maskb = 1;
> +    gen_load_gpr(num, rs);
> +    int x = 1;
> +    tcg_gen_andi_tl(res, num, maskb);
> +    tcg_gen_mov_tl(ones, res);
> 
> +    while (x <= 63) {
> +        tcg_gen_shri_i64(num, num, 1);
> +        tcg_gen_andi_tl(res, num, maskb);
> +        tcg_gen_add_tl(ones, ones, res);
> +        x++;
> +    }
> +    gen_store_gpr(ones, rd);
> +}
> +#endif
>  /* Godson integer instructions */
>  static void gen_loongson_integer (DisasContext *ctx, uint32_t opc,
>                                  int rd, int rs, int rt)
> @@ -2705,6 +3084,7 @@ static void gen_compute_branch (DisasContext *ctx,
> uint32_t opc,
>      target_ulong btgt = -1;
>      int blink = 0;
>      int bcond_compute = 0;
> +    target_ulong maskb; /* Used in BBIT0 and BBIT1*/
>      TCGv t0 = tcg_temp_new();
>      TCGv t1 = tcg_temp_new();
> 
> @@ -2730,6 +3110,39 @@ static void gen_compute_branch (DisasContext *ctx,
> uint32_t opc,
>          }
>          btgt = ctx->pc + insn_bytes + offset;
>          break;
> +    case OPC_BBIT1:
> +        gen_load_gpr(t0, rs);
> +        gen_load_gpr(t1, 0);
> +        maskb = 1ULL << rt;
> +        tcg_gen_andi_tl(t0, t0, maskb);
> +        bcond_compute = 1;
> +        btgt = ctx->pc + insn_bytes + offset;
> +        break;
> +    case OPC_BBIT132:
> +        gen_load_gpr(t0, rs);
> +        gen_load_gpr(t1, 0);
> +        maskb = 1ULL << (rt + 32);
> +        tcg_gen_andi_tl(t0, t0, maskb);
> +        bcond_compute = 1;
> +        btgt = ctx->pc + insn_bytes + offset;
> +        break;
> +    case OPC_BBIT0:
> +        gen_load_gpr(t0, rs);
> +        gen_load_gpr(t1, 0);
> +        maskb = 1ULL << rt;
> +        tcg_gen_andi_tl(t0, t0, maskb);
> +        bcond_compute = 1;
> +        btgt = ctx->pc + insn_bytes + offset;
> +        break;
> +    case OPC_BBIT032:
> +        gen_load_gpr(t0, rs);
> +        gen_load_gpr(t1, 0);
> +        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:
> @@ -2888,6 +3301,18 @@ 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:
> +            tcg_gen_setcond_tl(TCG_COND_NE, bcond, t0, t1);
> +            goto not_likely;
> +        case OPC_BBIT132:
> +            tcg_gen_setcond_tl(TCG_COND_NE, bcond, t0, t1);
> +            goto not_likely;
> +            case OPC_BBIT0:
> +            tcg_gen_setcond_tl(TCG_COND_EQ, bcond, t0, t1);
> +            goto not_likely;
> +        case OPC_BBIT032:
> +            tcg_gen_setcond_tl(TCG_COND_EQ, bcond, t0, t1);
> +            goto not_likely;
>          case OPC_BNEL:
>              tcg_gen_setcond_tl(TCG_COND_NE, bcond, t0, t1);
>              MIPS_DEBUG("bnel %s, %s, " TARGET_FMT_lx,
> @@ -2983,7 +3408,44 @@ static void gen_compute_branch (DisasContext *ctx,
> uint32_t opc,
>      tcg_temp_free(t0);
>      tcg_temp_free(t1);
>  }
> +/*For cavium specific extract instructions*/
> +#if defined(TARGET_MIPS64)
> +static void gen_exts (CPUState *env,DisasContext *ctx, uint32_t opc, int
> rt,
> +                      int rs, int lsb, int msb)
> +{
> +    TCGv t0 = tcg_temp_new();
> +    TCGv t1 = tcg_temp_new();
> +    target_ulong mask;
> +    gen_load_gpr(t1, rs);
> +    switch (opc) {
> +    case OPC_EXTS:
> +        tcg_gen_shri_tl(t0, t1, lsb);
> +        tcg_gen_andi_tl(t0, t0, (1ULL << (msb + 1)) - 1);
> +        /* To sign extened the remaining bits according to
> +           the msb of the bit field */
> +        mask = 1ULL << msb;
> +        tcg_gen_andi_tl(t1, t0, mask);
> +        tcg_gen_addi_tl(t1, t1, -1);
> +        tcg_gen_not_i64(t1, t1);
> +        tcg_gen_or_tl(t0, t0, t1);
> +        gen_store_gpr(t0, rt);
> +        break;
> +    case OPC_EXTS32:
> +        tcg_gen_shri_tl(t0, t1, lsb + 32);
> +        tcg_gen_andi_tl(t0, t0, (1ULL << (msb + 1)) - 1);
> +        mask = 1ULL << msb;
> +        tcg_gen_andi_tl(t1, t0, mask);
> +        tcg_gen_addi_tl(t1, t1, -1);
> +        tcg_gen_not_i64(t1, t1);
> +        tcg_gen_or_tl(t0, t0, t1);
> +        gen_store_gpr(t0, rt);
> +        break;
> 
> +    }
> +    tcg_temp_free(t0);
> +    tcg_temp_free(t1);
> +}
> +#endif
>  /* special3 bitfield operations */
>  static void gen_bitops (DisasContext *ctx, uint32_t opc, int rt,
>                          int rs, int lsb, int msb)
> @@ -3063,6 +3525,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:
> @@ -11605,7 +12083,7 @@ static void decode_opc (CPUState *env, DisasContext
> *ctx, int *is_branch)
>      int32_t offset;
>      int rs, rt, rd, sa;
>      uint32_t op, op1, op2;
> -    int16_t imm;
> +    int16_t imm, imm10;
> 
>      /* make sure instructions are on a word boundary */
>      if (ctx->pc & 0x3) {
> @@ -11634,6 +12112,9 @@ static void decode_opc (CPUState *env, DisasContext
> *ctx, int *is_branch)
>      rd = (ctx->opcode >> 11) & 0x1f;
>      sa = (ctx->opcode >> 6) & 0x1f;
>      imm = (int16_t)ctx->opcode;
> +    /* 10 bit Immediate value For SEQI,SNEI */
> +    imm10 = (ctx->opcode >> 6) & 0x3ff;
> +
>      switch (op) {
>      case OPC_SPECIAL:
>          op1 = MASK_SPECIAL(ctx->opcode);
> @@ -11859,6 +12340,71 @@ 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_insn(env, ctx, ISA_MIPS3);
> +            check_mips_64(ctx);
> +            gen_muldiv(ctx, op1, rs, rt);
> +            tcg_gen_mov_tl(cpu_gpr[rd], cpu_LO[0]);
> +            break;
> +        case OPC_CINS:
> +            check_insn(env, ctx, ISA_MIPS64R2);
> +            check_mips_64(ctx);
> +            gen_bitops(ctx, op1, rt, rs, sa, rd);
> +            break;
> +        case OPC_CINS32:
> +            check_mips_64(ctx);
> +            gen_bitops(ctx, op1, rt, rs, sa, rd);
> +            break;
> +        case OPC_MTM0:
> +            check_mips_64(ctx);
> +            gen_LMI(env, ctx, op1, rs, rt, rd);
> +            break;
> +        case OPC_MTM1:
> +            check_mips_64(ctx);
> +            gen_LMI(env, ctx, op1, rs, rt, rd);
> +            break;
> +        case OPC_MTM2:
> +            check_mips_64(ctx);
> +            gen_LMI(env, ctx, op1, rs, rt, rd);
> +            break;
> +        case OPC_MTP0:
> +            check_mips_64(ctx);
> +            gen_LMI(env, ctx, op1, rs, rt, rd);
> +            break;
> +        case OPC_MTP1:
> +            check_mips_64(ctx);
> +            gen_LMI(env, ctx, op1, rs, rt, rd);
> +            break;
> +        case OPC_MTP2:
> +            check_mips_64(ctx);
> +            gen_LMI(env, ctx, op1, rs, rt, rd);
> +            break;
> +        case OPC_VMULU:
> +            check_mips_64(ctx);
> +            gen_LMI(env, ctx, op1, rs, rt, rd);
> +            break;
> +        case OPC_BADDU:
> +            gen_arith(env, ctx, op1, rd, rs, rt);
> +            break;
> +        case OPC_EXTS:
> +            check_mips_64(ctx);
> +            gen_exts(env, ctx, op1, rt, rs, sa, rd);
> +            break;
> +        case OPC_EXTS32:
> +            check_mips_64(ctx);
> +            gen_exts(env, ctx, op1, rt, rs, sa, rd);
> +            break;
> +        case OPC_SAA:
> +            gen_saa(env, ctx, op1, rt, rs);
> +            break;
> +        case OPC_SAAD:
> +            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);
> @@ -11878,13 +12424,24 @@ static void decode_opc (CPUState *env,
> DisasContext *ctx, int *is_branch)
>              break;
>          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:
>              check_insn(env, ctx, INSN_LOONGSON2F);
>              gen_loongson_integer(ctx, op1, rd, rs, rt);
>              break;
> +        case OPC_MULT_G_2F:
> +            if (!TARGET_OCTEON) {
> +                check_insn(env, ctx, INSN_LOONGSON2F);
> +                gen_loongson_integer(ctx, op1, rd, rs, rt);
> +            } else {
> +#if defined(TARGET_MIPS64)
> +                /* Cavium Specific vmm0 */
> +                check_mips_64(ctx);
> +                gen_LMI(env, ctx, op1, rs, rt, rd);
> +#endif
> +            }
> +            break;
>  #if defined(TARGET_MIPS64)
>          case OPC_DCLO:
>          case OPC_DCLZ:
> @@ -11892,7 +12449,6 @@ static void decode_opc (CPUState *env, DisasContext
> *ctx, int *is_branch)
>              check_mips_64(ctx);
>              gen_cl(ctx, op1, rd, rs);
>              break;
> -        case OPC_DMULT_G_2F:
>          case OPC_DMULTU_G_2F:
>          case OPC_DDIV_G_2F:
>          case OPC_DDIVU_G_2F:
> @@ -11901,6 +12457,39 @@ 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_DMULT_G_2F:
> +            if (!TARGET_OCTEON) {
> +                check_insn(env, ctx, INSN_LOONGSON2F);
> +                gen_loongson_integer(ctx, op1, rd, rs, rt);
> +            } else {
> +                /* Cavium Specific instruction v3mulu */
> +                check_mips_64(ctx);
> +                gen_LMI(env, ctx, op1, rs, rt, rd);
> +            }
> +            break;
> +        case OPC_SEQ:
> +            check_mips_64(ctx);
> +            gen_seqsne(ctx, op1, rd, rs, rt);
> +            break;
> +        case OPC_SNE:
> +            check_mips_64(ctx);
> +            gen_seqsne(ctx, op1, rd, rs, rt);
> +            break;
> +        case OPC_SEQI:
> +            check_mips_64(ctx);
> +            gen_set_imm(env, op1, rt, rs, imm10);
> +            break;
> +        case OPC_SNEI:
> +            check_mips_64(ctx);
> +            gen_set_imm(env, op1, rt, rs, imm10);
> +            break;
> +        case OPC_POP:
> +            insn_opc_pop(ctx, env, op1, rd, rs, rt);
> +            break;
> +        case OPC_DPOP:
> +            check_mips_64(ctx);
> +            insn_opc_dpop(ctx, env, op1, rd, rs, rt);
> +            break;
>  #endif
>          default:            /* Invalid */
>              MIPS_INVAL("special2");
> @@ -12192,10 +12781,32 @@ 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 TARGET_OCTEON is set these opcodes will belong to Cavium */
> +    case OPC_LWC2: /*BBIT0*/
> +        if(TARGET_OCTEON) {
> +            gen_compute_branch(ctx, op, 4, rs, rt, imm << 2);
> +            *is_branch = 1;
> +            break;
> +        }
> +    case OPC_LDC2: /*BBIT032*/
> +        if(TARGET_OCTEON) {
> +            gen_compute_branch(ctx, op, 4, rs, rt, imm << 2);
> +            *is_branch = 1;
> +            break;
> +        }
> +    case OPC_SWC2: /*BBIT1*/
> +        if(TARGET_OCTEON) {
> +            gen_compute_branch(ctx, op, 4, rs, rt, imm << 2);
> +            *is_branch = 1;
> +            break;
> +        }
> +    case OPC_SDC2: /*BBIT132*/
> +        if(TARGET_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);
> @@ -12584,6 +13195,18 @@ static void mips_tcg_init(void)
>      cpu_dspctrl = tcg_global_mem_new(TCG_AREG0,
>                                       offsetof(CPUState,
> active_tc.DSPControl),
>                                       "DSPControl");
> +    mpl0 = tcg_global_mem_new(TCG_AREG0,
> +                              offsetof(CPUState, Reg.MPL0), "MPL0");
> +    mpl1 = tcg_global_mem_new(TCG_AREG0,
> +                              offsetof(CPUState, Reg.MPL1), "MPL1");
> +    mpl2 = tcg_global_mem_new(TCG_AREG0,
> +                              offsetof(CPUState, Reg.MPL2), "MPL2");
> +    p0 = tcg_global_mem_new(TCG_AREG0,
> +                            offsetof(CPUState, Reg.P0), "P0");
> +    p1 = tcg_global_mem_new(TCG_AREG0,
> +                            offsetof(CPUState, Reg.P1), "P1");
> +    p2 = tcg_global_mem_new(TCG_AREG0,
> +                            offsetof(CPUState, Reg.P2), "P2");
>      bcond = tcg_global_mem_new(TCG_AREG0,
>                                 offsetof(CPUState, bcond), "bcond");
>      btarget = tcg_global_mem_new(TCG_AREG0,
> @@ -12607,6 +13230,18 @@ static void mips_tcg_init(void)
> 
>  #include "translate_init.c"
> 
> +#if defined(TARGET_MIPS64)
> +
> +static void set_cvmctl_register(CPUMIPSState *env)
> +{
> +    env->CvmCtlRegister.cvmctl = env->CvmCtlRegister.cvmctl
> +                                 ^ env->CvmCtlRegister.cvmctl;
> +    env->CvmCtlRegister.cvmctl =
> FUSE_START_BIT(env->CvmCtlRegister.cvmctl);
> +    env->CvmCtlRegister.cvmctl = KASUMI(env->CvmCtlRegister.cvmctl);
> +    env->CvmCtlRegister.cvmctl = IPPCI(env->CvmCtlRegister.cvmctl);
> +    env->CvmCtlRegister.cvmctl = IPTI(env->CvmCtlRegister.cvmctl);
> +}
> +#endif
>  CPUMIPSState *cpu_mips_init (const char *cpu_model)
>  {
>      CPUMIPSState *env;
> @@ -12619,6 +13254,10 @@ CPUMIPSState *cpu_mips_init (const char *cpu_model)
>      env->cpu_model = def;
>      env->cpu_model_str = cpu_model;
> 
> +#if defined(TARGET_MIPS64)
> +    /*Function for setting cvmctl register*/
> +    set_cvmctl_register(env);
> +#endif
>      cpu_exec_init(env);
>  #ifndef CONFIG_USER_ONLY
>      mmu_init(env, def);
> -- 
> 1.7.3.4
maheen butt March 29, 2011, 10:49 a.m. UTC | #2
hiThanks for your review. I have Cavium Networks Octeon board so I can provide you MIPS64 bit binaries. I can not understand the second thing. if my concern is to reduce the patch size then again target-mips changes patch will produce a bigger sized patch because my major changes are in target-mips(translate.c).. so please guide me what should I do. I think Implementation of Octeon specific instruction should be in single patch what do you say?PS- 

--- On Tue, 3/29/11, Riku Voipio <riku.voipio@iki.fi> wrote:

From: Riku Voipio <riku.voipio@iki.fi>
Subject: Re: [Qemu-devel] MIPS64 user mode emulation Patch
To: "Khansa Butt" <khansa@kics.edu.pk>
Cc: qemu-devel@nongnu.org
Date: Tuesday, March 29, 2011, 1:55 AM

Hi,

First, do you have some instructions on howto build Octeon usermode
64bit binaries. Second, I think we would prefer that the patch was split
to smaller patches. At least the target-mips changes should be a separate
patch.

Some more comments included inline between the code.

On Sat, Mar 26, 2011 at 11:58:37AM +0500, Khansa Butt wrote:
> >From cd88be1263d0fc9802cd4dd358ed0299c0d106b0 Mon Sep 17 00:00:00 2001
> From: Khansa Butt & Ehsan-ul-Haq <khansa@kics.edu.pk>
> Date: Sat, 26 Mar 2011 11:53:11 +0500
> Subject: [PATCH] MIPS64 user mode emulation in QEMU
>  This patch adds support for Cavium Network's
>  Octeon 57XX user mode instructions.  Octeon
>  57xx is based on MIPS64.  So this patch is
>  the first MIPS64 User Mode Emulation in QEMU
>  This is the team(Khansa Butt, Ehsan-ul-Haq, Abdul Qadeer, Abdul Waheed)
>  work of HPCNL Lab at KICS-UET Lahore.
> 
> 
> Signed-off-by: Khansa Butt <khansa@kics.edu.pk>
> ---
>  configure                             |    1 +
>  default-configs/mips64-linux-user.mak |    1 +
>  exec.c                                |    1 +
>  linux-user/elfload.c                  |   15 +-
>  linux-user/main.c                     |   20 +-
>  linux-user/mips64/syscall.h           |    2 +
>  linux-user/signal.c                   |    3 +-
>  linux-user/syscall.c                  |    2 +
>  target-mips/cpu.h                     |   16 +
>  target-mips/translate.c               |  659
> ++++++++++++++++++++++++++++++++-
>  10 files changed, 704 insertions(+), 16 deletions(-)
>  create mode 100644 default-configs/mips64-linux-user.mak
> 
> diff --git a/configure b/configure
> index 438219b..045a4ef 100755
> --- a/configure
> +++ b/configure
> @@ -1011,6 +1011,7 @@ cris-linux-user \
>  m68k-linux-user \
>  microblaze-linux-user \
>  mips-linux-user \
> +mips64-linux-user \
>  mipsel-linux-user \
>  ppc-linux-user \
>  ppc64-linux-user \
> diff --git a/default-configs/mips64-linux-user.mak
> b/default-configs/mips64-linux-user.mak
> new file mode 100644
> index 0000000..1598bfc
> --- /dev/null
> +++ b/default-configs/mips64-linux-user.mak
> @@ -0,0 +1 @@
> +# Default configuration for mips64-linux-user
> diff --git a/exec.c b/exec.c
> index 49c28b1..ee3f78e 100644
> --- a/exec.c
> +++ b/exec.c
> @@ -2441,6 +2441,7 @@ int page_check_range(target_ulong start, target_ulong
> len, int flags)
>      for (addr = start, len = end - start;
>           len != 0;
>           len -= TARGET_PAGE_SIZE, addr += TARGET_PAGE_SIZE) {
> +        addr  &= qemu_host_page_mask;
>          p = page_find(addr >> TARGET_PAGE_BITS);

Are you sure this will not generate ill effect on other target/host architecture
combinations?

>          if( !p )
>              return -1;
> diff --git a/linux-user/elfload.c b/linux-user/elfload.c
> index 33d776d..60fe85e 100644
> --- a/linux-user/elfload.c
> +++ b/linux-user/elfload.c
> @@ -16,6 +16,8 @@
>  #include "qemu.h"
>  #include "disas.h"
> 
> +extern int TARGET_OCTEON;
> +
>  #ifdef _ARCH_PPC64
>  #undef ARCH_DLINFO
>  #undef ELF_PLATFORM
> @@ -25,6 +27,9 @@
>  #undef ELF_ARCH
>  #endif
> 
> +#define EF_MIPS_MARCH 16711680
> +#define E_MIPS_MACH_OCTEON 9109504
> +

please use hexadecimal values.

>  #define ELF_OSABI   ELFOSABI_SYSV
> 
>  /* from personality.h */
> @@ -1313,7 +1318,7 @@ static void load_elf_image(const char *image_name, int
> image_fd,
>              vaddr_po = TARGET_ELF_PAGEOFFSET(vaddr);
>              vaddr_ps = TARGET_ELF_PAGESTART(vaddr);
> 
> -            error = target_mmap(vaddr_ps, eppnt->p_filesz + vaddr_po,
> +            error = target_mmap(vaddr_ps, eppnt->p_memsz + vaddr_po,
>                                  elf_prot, MAP_PRIVATE | MAP_FIXED,
>                                  image_fd, eppnt->p_offset - vaddr_po);
>              if (error == -1) {
> @@ -1588,7 +1593,13 @@ int load_elf_binary(struct linux_binprm * bprm,
> struct target_pt_regs * regs,
>         If we do nothing, we'll have overwritten this when we re-use
> bprm->buf
>         when we load the interpreter.  */
>      elf_ex = *(struct elfhdr *)bprm->buf;
> -
> +#if defined(TARGET_MIPS64)
> +    if ((elf_ex.e_flags & EF_MIPS_MARCH) == E_MIPS_MACH_OCTEON) {
> +        TARGET_OCTEON = 1;
> +    } else {
> +        TARGET_OCTEON = 0;
> +    }
> +#endif
>      bprm->p = copy_elf_strings(1, &bprm->filename, bprm->page, bprm->p);
>      bprm->p = copy_elf_strings(bprm->envc,bprm->envp,bprm->page,bprm->p);
>      bprm->p = copy_elf_strings(bprm->argc,bprm->argv,bprm->page,bprm->p);
> diff --git a/linux-user/main.c b/linux-user/main.c
> index 0d627d6..8b4b90b 100644
> --- a/linux-user/main.c
> +++ b/linux-user/main.c
> @@ -1937,10 +1937,16 @@ static int do_store_exclusive(CPUMIPSState *env)
>      int d;
> 
>      addr = env->lladdr;
> +    /* 64 bit address is converted to 32 bit value so that a valid
> +    * l1_map value can be accessed. This thing is needed for target
> +    * mips64 and host 32 bit x86
> +    */
> +    addr &= qemu_host_page_mask;

same as earlier.

>      page_addr = addr & TARGET_PAGE_MASK;
>      start_exclusive();
>      mmap_lock();
>      flags = page_get_flags(page_addr);
> +    addr = env->lladdr;
>      if ((flags & PAGE_READ) == 0) {
>          segv = 1;
>      } else {
> @@ -1978,7 +1984,8 @@ static int do_store_exclusive(CPUMIPSState *env)
>  void cpu_loop(CPUMIPSState *env)
>  {
>      target_siginfo_t info;
> -    int trapnr, ret;
> +    int trapnr;
> +    abi_long ret;
>      unsigned int syscall_num;
> 
>      for(;;) {
> @@ -1987,7 +1994,11 @@ void cpu_loop(CPUMIPSState *env)
>          cpu_exec_end(env);
>          switch(trapnr) {
>          case EXCP_SYSCALL:
> +#if defined(TARGET_MIPS64)
> +            syscall_num = env->active_tc.gpr[2] - 5000;
> +#else
>              syscall_num = env->active_tc.gpr[2] - 4000;
> +#endif
>              env->active_tc.PC += 4;
>              if (syscall_num >= sizeof(mips_syscall_args)) {
>                  ret = -ENOSYS;
> @@ -2013,7 +2024,8 @@ void cpu_loop(CPUMIPSState *env)
>                                   env->active_tc.gpr[5],
>                                   env->active_tc.gpr[6],
>                                   env->active_tc.gpr[7],
> -                                 arg5, arg6/*, arg7, arg8*/);
> +                                 env->active_tc.gpr[8],
> +                                 env->active_tc.gpr[9]/*, arg7, arg8*/);
>              }
>              if (ret == -TARGET_QEMU_ESIGRETURN) {
>                  /* Returning from a successful sigreturn syscall.
> @@ -2926,7 +2938,9 @@ int main(int argc, char **argv, char **envp)
>  #endif
>  #elif defined(TARGET_MIPS)
>  #if defined(TARGET_ABI_MIPSN32) || defined(TARGET_ABI_MIPSN64)
> -        cpu_model = "20Kc";
> +        /* we use this model so that we can decode MIPS64r2
> +           reserved instruction */
> +        cpu_model = "MIPS64R2-generic";
>  #else
>          cpu_model = "24Kf";
>  #endif
> diff --git a/linux-user/mips64/syscall.h b/linux-user/mips64/syscall.h
> index 668a2b9..1395e61 100644
> --- a/linux-user/mips64/syscall.h
> +++ b/linux-user/mips64/syscall.h
> @@ -217,5 +217,7 @@ struct target_pt_regs {
>  #define TARGET_ENOTRECOVERABLE 166     /* State not recoverable */
> 
> 
> +/* Nasty hack: define a fake errno value for use by sigreturn.  */
> +#define TARGET_QEMU_ESIGRETURN 255
> 
>  #define UNAME_MACHINE "mips64"
> diff --git a/linux-user/signal.c b/linux-user/signal.c
> index c846b8c..114116c 100644
> --- a/linux-user/signal.c
> +++ b/linux-user/signal.c
> @@ -2410,7 +2410,8 @@ void sparc64_get_context(CPUSPARCState *env)
>  #endif
>  #elif defined(TARGET_ABI_MIPSN64)
> 
> -# warning signal handling not implemented
> +/*this line is commented out to avoid compile time error*/
> +/*# warning signal handling not implemented*/
> 
>  static void setup_frame(int sig, struct target_sigaction *ka,
>   target_sigset_t *set, CPUState *env)
> diff --git a/linux-user/syscall.c b/linux-user/syscall.c
> index 499c4d7..47fef05 100644
> --- a/linux-user/syscall.c
> +++ b/linux-user/syscall.c
> @@ -7195,6 +7195,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long
> arg1,
>      case TARGET_NR_set_thread_area:
>  #if defined(TARGET_MIPS)
>        ((CPUMIPSState *) cpu_env)->tls_value = arg1;
> +       /*tls entry is moved to k0 so that this can be used later*/
> +      ((CPUMIPSState *) cpu_env)->active_tc.gpr[26] = arg1;

Does this affect the non-octeon mips ?

>        ret = 0;
>        break;
>  #elif defined(TARGET_CRIS)

And someone else will need to comment the TCG changes.

> diff --git a/target-mips/cpu.h b/target-mips/cpu.h
> index 2419aa9..59bcc0f 100644
> --- a/target-mips/cpu.h
> +++ b/target-mips/cpu.h
> @@ -140,6 +140,20 @@ typedef struct mips_def_t mips_def_t;
>  #define MIPS_FPU_MAX 1
>  #define MIPS_DSP_ACC 4
> 
> +typedef struct cavium_mul cavium_mul;
> +struct cavium_mul {
> + target_ulong MPL0;
> + target_ulong MPL1;
> + target_ulong MPL2;
> + target_ulong P0;
> + target_ulong P1;
> + target_ulong P2;
> +};
> +typedef struct cvmctl_register cvmctl_register;
> +struct cvmctl_register {
> + target_ulong cvmctl;
> +};
> +
>  typedef struct TCState TCState;
>  struct TCState {
>      target_ulong gpr[32];
> @@ -178,6 +192,8 @@ struct CPUMIPSState {
>      TCState active_tc;
>      CPUMIPSFPUContext active_fpu;
> 
> +    cavium_mul Reg;
> +    cvmctl_register CvmCtlRegister;
>      uint32_t current_tc;
>      uint32_t current_fpu;
> 
> diff --git a/target-mips/translate.c b/target-mips/translate.c
> index cce77be..9c3d772 100644
> --- a/target-mips/translate.c
> +++ b/target-mips/translate.c
> @@ -36,6 +36,15 @@
>  #define GEN_HELPER 1
>  #include "helper.h"
> 
> +int TARGET_OCTEON;
> +#if defined(TARGET_MIPS64)
> +/*Macros for setting values of cvmctl registers*/
> +#define FUSE_START_BIT(cvmctl)(cvmctl | 0x80000000)
> +#define KASUMI(cvmctl)(cvmctl | 0x20000000)
> +#define IPPCI(cvmctl)(cvmctl | 0x380)
> +#define IPTI(cvmctl)(cvmctl | 0x70)
> +#endif
> +
>  //#define MIPS_DEBUG_DISAS
>  //#define MIPS_DEBUG_SIGN_EXTENSIONS
> 
> @@ -70,6 +79,11 @@ enum {
>      OPC_JAL      = (0x03 << 26),
>      OPC_JALS     = OPC_JAL | 0x5,
>      OPC_BEQ      = (0x04 << 26),  /* Unconditional if rs = rt = 0 (B) */
> +    /* Cavium Specific */
> +    OPC_BBIT1    = (0x3a << 26),  /*jump on bit set, cavium specific*/
> +    OPC_BBIT132  = (0x3e << 26),  /*jump on bit set(one of the upper 32
> bits)*/
> +    OPC_BBIT0    = (0x32 << 26),  /*jump on bit clear, cavium specific*/
> +    OPC_BBIT032  = (0x36 << 26),  /*jump on bit set(one of the upper 32
> bits)*/
>      OPC_BEQL     = (0x14 << 26),
>      OPC_BNE      = (0x05 << 26),
>      OPC_BNEL     = (0x15 << 26),
> @@ -265,6 +279,31 @@ enum {
>      OPC_MADD     = 0x00 | OPC_SPECIAL2,
>      OPC_MADDU    = 0x01 | OPC_SPECIAL2,
>      OPC_MUL      = 0x02 | 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,
> +/**************************************/
>      OPC_MSUB     = 0x04 | OPC_SPECIAL2,
>      OPC_MSUBU    = 0x05 | OPC_SPECIAL2,
>      /* Loongson 2F */
> @@ -483,7 +522,7 @@ enum {
>  static TCGv_ptr cpu_env;
>  static TCGv cpu_gpr[32], cpu_PC;
>  static TCGv cpu_HI[MIPS_DSP_ACC], cpu_LO[MIPS_DSP_ACC],
> cpu_ACX[MIPS_DSP_ACC];
> -static TCGv cpu_dspctrl, btarget, bcond;
> +static TCGv cpu_dspctrl, btarget, bcond, mpl0, mpl1, mpl2, p0, p1, p2;
>  static TCGv_i32 hflags;
>  static TCGv_i32 fpu_fcr0, fpu_fcr31;
> 
> @@ -779,7 +818,9 @@ static inline void gen_op_addr_add (DisasContext *ctx,
> TCGv ret, TCGv arg0, TCGv
>         See the MIPS64 PRA manual, section 4.10. */
>      if (((ctx->hflags & MIPS_HFLAG_KSU) == MIPS_HFLAG_UM) &&
>          !(ctx->hflags & MIPS_HFLAG_UX)) {
> -        tcg_gen_ext32s_i64(ret, ret);
> +        /*This function sign extend 32 bit value to 64 bit, was causing
> error
> +          when ld instruction came.Thats why it is commmented out*/
> +       /* tcg_gen_ext32s_i64(ret, ret);*/
>      }
>  #endif
>  }
> @@ -1419,7 +1460,33 @@ static void gen_arith_imm (CPUState *env,
> DisasContext *ctx, uint32_t opc,
>      (void)opn; /* avoid a compiler warning */
>      MIPS_DEBUG("%s %s, %s, " TARGET_FMT_lx, opn, regnames[rt],
> regnames[rs], uimm);
>  }
> -
> +#if defined(TARGET_MIPS64)
> +/*set on equal immidiate/seton not equal immidiate*/
> +static void gen_set_imm(CPUState *env, uint32_t opc, int rt, int rs,
> int16_t imm)
> +{
> +    target_ulong uimm;
> +    TCGv t0, t1;
> +    const char *opn = "imm set";
> +    uimm = (uint16_t)imm;
> +    t0 = tcg_temp_new();
> +    t1 = tcg_temp_new();
> +    switch (opc) {
> +    case OPC_SEQI:
> +        tcg_gen_xori_tl(cpu_gpr[rt], cpu_gpr[rs], uimm);
> +        gen_load_gpr(t0, rt);
> +        tcg_gen_setcondi_tl(TCG_COND_LTU, cpu_gpr[rt], t0, 1);
> +        opn = "seqi";
> +        break;
> +    case OPC_SNEI:
> +        tcg_gen_xori_tl(cpu_gpr[rt], cpu_gpr[rs], uimm);
> +        gen_load_gpr(t0, rt);
> +        gen_load_gpr(t1, 0);
> +        tcg_gen_setcond_tl(TCG_COND_LTU, cpu_gpr[rt], t1, t0);
> +        opn = "snei";
> +        break;
> +    }
> +}
> +#endif
>  /* Logic with immediate operand */
>  static void gen_logic_imm (CPUState *env, uint32_t opc, int rt, int rs,
> int16_t imm)
>  {
> @@ -1583,13 +1650,196 @@ static void gen_shift_imm(CPUState *env,
> DisasContext *ctx, uint32_t opc,
>      MIPS_DEBUG("%s %s, %s, " TARGET_FMT_lx, opn, regnames[rt],
> regnames[rs], uimm);
>      tcg_temp_free(t0);
>  }
> +#if defined(TARGET_MIPS64)
> +/* Addition and carry detection*/
> +static void gen_addc (TCGv arg1, TCGv arg2, TCGv res, TCGv c)
> +{
> +    tcg_gen_add_tl(res, arg1, arg2);
> +    tcg_gen_setcond_tl(TCG_COND_LTU, c, res, arg1);
> +}
> +static void gen_LMI (CPUMIPSState *env, DisasContext *ctx, uint32_t opc,
> +                 int rs, int rt, int rd)
> +{
> +    const char *opn = "LMI";
> +    TCGv t0, t1;
> +    int nomul = env->CvmCtlRegister.cvmctl & 0x8000000;
> +    if (!nomul) {
> +        switch (opc) {
> +        case OPC_MTM0:
> +            tcg_gen_mov_tl(mpl0, cpu_gpr[rs]);
> +            tcg_gen_movi_tl(p0, 0);
> +            tcg_gen_movi_tl(p1, 0);
> +            tcg_gen_movi_tl(p2, 0);
> +            opn = "mtm0";
> +            break;
> +        case OPC_MTM1:
> +            tcg_gen_mov_tl(mpl1, cpu_gpr[rs]);
> +            tcg_gen_movi_tl(p0, 0);
> +            tcg_gen_movi_tl(p1, 0);
> +            tcg_gen_movi_tl(p2, 0);
> +            opn = "mtm1";
> +            break;
> +        case OPC_MTM2:
> +            tcg_gen_mov_tl(mpl2, cpu_gpr[rs]);
> +            tcg_gen_movi_tl(p0, 0);
> +            tcg_gen_movi_tl(p1, 0);
> +            tcg_gen_movi_tl(p2, 0);
> +            opn = "mtm2";
> +            break;
> +        case OPC_MTP0:
> +            tcg_gen_mov_tl(p0, cpu_gpr[rs]);
> +            opn = "mtp0";
> +            break;
> +        case OPC_MTP1:
> +            tcg_gen_mov_tl(p1, cpu_gpr[rs]);
> +            opn = "mtp1";
> +            break;
> +        case OPC_MTP2:
> +            tcg_gen_mov_tl(p2, cpu_gpr[rs]);
> +            opn = "mtp2";
> +            break;
> +        case OPC_VMM0:
> +            t0 = tcg_temp_new();
> +            t1 = tcg_temp_new();
> +            gen_load_gpr(t1, rs);
> +            gen_helper_dmultu(t1, mpl0);
> +            gen_load_gpr(t0, rt);
> +            tcg_gen_add_tl(t0, t0, cpu_LO[0]);
> +            tcg_gen_add_tl(t0, t0, p0);
> +            gen_store_gpr(t0, rd);
> +            tcg_gen_mov_tl(mpl0, cpu_gpr[rd]);
> +            tcg_gen_movi_tl(p0, 0);
> +            tcg_gen_movi_tl(p1, 0);
> +            tcg_gen_movi_tl(p2, 0);
> +            tcg_temp_free(t0);
> +            tcg_temp_free(t1);
> +            opn = "vmm0";
> +            break;
> +        case OPC_VMULU:
> +            {
> +                TCGv t2, c;
> +                t0 = tcg_temp_new();
> +                t1 = tcg_temp_new();
> +                t2 = tcg_temp_new();
> +                c = tcg_temp_new();
> +                gen_load_gpr(t1, rs);
> +                gen_load_gpr(t2, rt);
> +                gen_helper_dmultu(t1, mpl0);
> +                tcg_gen_mov_tl(t0, cpu_LO[0]);
> +                /*if carry comes due to addition of rt and LO register,
> +                 * this carry should be added to HI register.
> +                 */
> +                gen_addc(t0, t2, t1, c);
> 
> +                tcg_gen_add_tl(cpu_HI[0], cpu_HI[0], c);
> +                /* t0 = t1 + p0 where t1 = LO+rt*/
> +                gen_addc(t1, p0, t0, c);
> +                tcg_gen_add_tl(cpu_HI[0], cpu_HI[0], c);
> +
> +                tcg_gen_mov_tl(cpu_gpr[rd], t0);
> +                tcg_gen_mov_tl(p0, cpu_HI[0]);
> +                tcg_temp_free(t0);
> +                tcg_temp_free(t1);
> +                tcg_temp_free(t2);
> +                opn = "vmulu";
> +                break;
> +            }
> +        case OPC_V3MULU:
> +            {
> +                TCGv temp[4];
> +                TCGv c;
> +                TCGv trs, trt, tc1, tc2, tc3;
> +                temp[0] = tcg_temp_new();
> +                temp[1] = tcg_temp_new();
> +                temp[2] = tcg_temp_new();
> +                temp[3] = tcg_temp_new();
> +                trs = tcg_temp_new();
> +                trt = tcg_temp_new();
> +                tc1 = tcg_temp_new();
> +                tc2 = tcg_temp_new();
> +                tc3 = tcg_temp_new();
> +                c = tcg_temp_new();
> +                gen_load_gpr(trs, rs);
> +                gen_load_gpr(trt, rt);
> +                /* rs × (MPL2 || MPL1 || MPL0) (192X64 bit multiplication)
> */
> +                gen_helper_dmultu(trs, mpl0);
> +                tcg_gen_mov_tl(temp[0], cpu_LO[0]);
> +                tcg_gen_mov_tl(temp[1], cpu_HI[0]);
> +
> +                gen_helper_dmultu(trs, mpl1);
> +                tcg_gen_mov_tl(temp[2], cpu_HI[0]);
> +                gen_addc(cpu_LO[0], temp[1], tc1, tc2);
> +                gen_addc(temp[2], tc2, tc3, c);
> +                tcg_gen_mov_tl(temp[1], tc1);
> +                tcg_gen_mov_tl(temp[2], tc3);
> +                tcg_gen_mov_tl(temp[3], c);
> +
> +                gen_helper_dmultu(trs, mpl2);
> +                tcg_gen_add_tl(temp[3], temp[3], cpu_HI[0]);
> +                gen_addc(cpu_LO[0], temp[2], tc1, tc2);
> +                tcg_gen_mov_tl(temp[2], tc1);
> +                tcg_gen_add_tl(temp[3], temp[3], tc2);
> +                /* Addition of rt in 256 bit result
> +                  (t3 t2 t1 t0 contain result) */
> +                gen_addc(temp[0], trt, tc1, c);
> +                tcg_gen_mov_tl(temp[0], tc1);
> +                gen_addc(temp[1], c, tc1, tc2);
> +                tcg_gen_mov_tl(temp[1], tc1);
> +                gen_addc(temp[2], tc2, tc1, c);
> +                tcg_gen_mov_tl(temp[2], tc1);
> +                tcg_gen_add_tl(temp[3], temp[3], c);
> +                /* Addition of p2 p1 p0 in 256 bit result */
> +                gen_addc(temp[0], p0, tc1, c);
> +                tcg_gen_mov_tl(temp[0], tc1);
> +                gen_addc(temp[1], c, tc1, tc2);
> +                tcg_gen_mov_tl(temp[1], tc1);
> +                gen_addc(temp[2], tc2, tc1, c);
> +                tcg_gen_mov_tl(temp[2], tc1);
> +                tcg_gen_add_tl(temp[3], temp[3], c);
> +
> +                gen_addc(temp[1], p1, tc1, c);
> +                tcg_gen_mov_tl(temp[1], tc1);
> +                gen_addc(temp[2], c, tc1, tc2);
> +                tcg_gen_mov_tl(temp[2], tc1);
> +                tcg_gen_add_tl(temp[3], temp[3], tc2);
> +
> +                gen_addc(temp[2], p2, tc1, c);
> +                tcg_gen_mov_tl(temp[2], tc1);
> +                tcg_gen_add_tl(temp[3], temp[3], c);
> +                /* final step */
> +                tcg_gen_mov_tl(cpu_gpr[rd], temp[0]);
> +                tcg_gen_mov_tl(p0, temp[1]);
> +                tcg_gen_mov_tl(p1, temp[2]);
> +                tcg_gen_mov_tl(p2, temp[3]);
> +                tcg_temp_free(temp[0]);
> +                tcg_temp_free(temp[1]);
> +                tcg_temp_free(temp[2]);
> +                tcg_temp_free(temp[3]);
> +                tcg_temp_free(trs);
> +                tcg_temp_free(trt);
> +                tcg_temp_free(tc1);
> +                tcg_temp_free(tc2);
> +                tcg_temp_free(tc3);
> +                tcg_temp_free(c);
> +                opn = "v3mulu";
> +                break;
> +            }
> +        }
> +
> +    } else {
> +        generate_exception(ctx, EXCP_RI);
> +    }
> +}
> +
> +
> +#endif
>  /* Arithmetic */
>  static void gen_arith (CPUState *env, DisasContext *ctx, uint32_t opc,
>                         int rd, int rs, int rt)
>  {
>      const char *opn = "arith";
> 
> +    target_ulong mask = 0xFF;
>      if (rd == 0 && opc != OPC_ADD && opc != OPC_SUB
>         && opc != OPC_DADD && opc != OPC_DSUB) {
>          /* If no destination, treat it as a NOP.
> @@ -1637,6 +1887,22 @@ 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();
> +            TCGv t2 = tcg_temp_new();
> +            gen_load_gpr(t1, rs);
> +            gen_load_gpr(t2, rt);
> +            tcg_gen_andi_tl(t1, t1, mask);
> +            tcg_gen_andi_tl(t2, t2, mask);
> +            tcg_gen_add_tl(t0, t1, t2);
> +            tcg_gen_andi_tl(t0, t0, mask);
> +            gen_store_gpr(t0, rd);
> +        }
> +
> +       opn = "baddu";
> +       break;
>      case OPC_SUB:
>          {
>              TCGv t0 = tcg_temp_local_new();
> @@ -2013,7 +2279,74 @@ static void gen_HILO (DisasContext *ctx, uint32_t
> opc, int reg)
>      (void)opn; /* avoid a compiler warning */
>      MIPS_DEBUG("%s %s", opn, regnames[reg]);
>  }
> +#if defined(TARGET_MIPS64)
> +static void gen_seqsne (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();
> +    switch (opc) {
> +    case OPC_SEQ:
> +        {
> +            tcg_gen_xor_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]);
> +            gen_load_gpr(t0, rd);
> +            tcg_gen_setcondi_tl(TCG_COND_LTU, cpu_gpr[rd], t0, 1);
> +        }
> +        opn = "seq";
> +        break;
> +    case OPC_SNE:
> +        {
> +            tcg_gen_xor_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]);
> +            gen_load_gpr(t0, rd);
> +            gen_load_gpr(t1, 0);
> +            tcg_gen_setcond_tl(TCG_COND_LTU, cpu_gpr[rd], t1, t0);
> +        }
> +        opn = "sne";
> +        break;
> +    default:
> +        MIPS_INVAL(opn);
> +        generate_exception(ctx, EXCP_RI);
> +        goto out;
> +    }
> +out:
> +        tcg_temp_free(t0);
> +        tcg_temp_free(t1);
> 
> +}
> +
> +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_lw(temp, t0, ctx);
> +        tcg_gen_add_tl(temp, temp, t1);
> +        op_st_sw(temp, t0, ctx);
> +        opn = "saa";
> +        break;
> +    case OPC_SAAD:
> +        save_cpu_state(ctx, 0);
> +        op_ld_ld(temp, t0, ctx);
> +        tcg_gen_add_tl(temp, temp, t1);
> +        op_st_sd(temp, t0, ctx);
> +        opn = "saad";
> +        break;
> +    }
> +
> +    tcg_temp_free(t0);
> +    tcg_temp_free(t1);
> +}
> +#endif
>  static void gen_muldiv (DisasContext *ctx, uint32_t opc,
>                          int rs, int rt)
>  {
> @@ -2149,6 +2482,10 @@ static void gen_muldiv (DisasContext *ctx, uint32_t
> opc,
>          gen_helper_dmult(t0, t1);
>          opn = "dmult";
>          break;
> +    case OPC_DMUL:
> +        gen_helper_dmult(t0, t1);
> +        opn = "dmul";
> +        break;
>      case OPC_DMULTU:
>          gen_helper_dmultu(t0, t1);
>          opn = "dmultu";
> @@ -2368,7 +2705,49 @@ static void gen_cl (DisasContext *ctx, uint32_t opc,
>      MIPS_DEBUG("%s %s, %s", opn, regnames[rd], regnames[rs]);
>      tcg_temp_free(t0);
>  }
> +#if defined(TARGET_MIPS64)
> +static void insn_opc_pop (DisasContext *ctx, CPUState *env, uint32_t opc,
> +                          int rd, int rs, int rt)
> +{
> +    TCGv num = tcg_temp_new();
> +    TCGv res = tcg_temp_new();
> +    target_ulong maskb = 1;
> +    gen_load_gpr(num, rs);
> +    TCGv ones=tcg_temp_new();
> +    gen_load_gpr(ones, 0);
> +    int x=1;
> +    tcg_gen_andi_tl(res, num, maskb);
> +    tcg_gen_add_tl(ones,ones, res);
> +    while (x <= 31) {
> +        tcg_gen_shri_i64(num, num, 1);
> +        tcg_gen_andi_tl(res, num, maskb);
> +        tcg_gen_add_tl(ones, ones, res);
> +        x++;
> +    }
> +    gen_store_gpr(ones, rd);
> +}
> +static void insn_opc_dpop (DisasContext *ctx, CPUState *env, uint32_t opc,
> +                           int rd, int rs, int rt)
> +{
> +    TCGv num, res, ones;
> +    num = tcg_temp_new();
> +    res = tcg_temp_new();
> +    ones = tcg_temp_new();
> +    target_ulong maskb = 1;
> +    gen_load_gpr(num, rs);
> +    int x = 1;
> +    tcg_gen_andi_tl(res, num, maskb);
> +    tcg_gen_mov_tl(ones, res);
> 
> +    while (x <= 63) {
> +        tcg_gen_shri_i64(num, num, 1);
> +        tcg_gen_andi_tl(res, num, maskb);
> +        tcg_gen_add_tl(ones, ones, res);
> +        x++;
> +    }
> +    gen_store_gpr(ones, rd);
> +}
> +#endif
>  /* Godson integer instructions */
>  static void gen_loongson_integer (DisasContext *ctx, uint32_t opc,
>                                  int rd, int rs, int rt)
> @@ -2705,6 +3084,7 @@ static void gen_compute_branch (DisasContext *ctx,
> uint32_t opc,
>      target_ulong btgt = -1;
>      int blink = 0;
>      int bcond_compute = 0;
> +    target_ulong maskb; /* Used in BBIT0 and BBIT1*/
>      TCGv t0 = tcg_temp_new();
>      TCGv t1 = tcg_temp_new();
> 
> @@ -2730,6 +3110,39 @@ static void gen_compute_branch (DisasContext *ctx,
> uint32_t opc,
>          }
>          btgt = ctx->pc + insn_bytes + offset;
>          break;
> +    case OPC_BBIT1:
> +        gen_load_gpr(t0, rs);
> +        gen_load_gpr(t1, 0);
> +        maskb = 1ULL << rt;
> +        tcg_gen_andi_tl(t0, t0, maskb);
> +        bcond_compute = 1;
> +        btgt = ctx->pc + insn_bytes + offset;
> +        break;
> +    case OPC_BBIT132:
> +        gen_load_gpr(t0, rs);
> +        gen_load_gpr(t1, 0);
> +        maskb = 1ULL << (rt + 32);
> +        tcg_gen_andi_tl(t0, t0, maskb);
> +        bcond_compute = 1;
> +        btgt = ctx->pc + insn_bytes + offset;
> +        break;
> +    case OPC_BBIT0:
> +        gen_load_gpr(t0, rs);
> +        gen_load_gpr(t1, 0);
> +        maskb = 1ULL << rt;
> +        tcg_gen_andi_tl(t0, t0, maskb);
> +        bcond_compute = 1;
> +        btgt = ctx->pc + insn_bytes + offset;
> +        break;
> +    case OPC_BBIT032:
> +        gen_load_gpr(t0, rs);
> +        gen_load_gpr(t1, 0);
> +        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:
> @@ -2888,6 +3301,18 @@ 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:
> +            tcg_gen_setcond_tl(TCG_COND_NE, bcond, t0, t1);
> +            goto not_likely;
> +        case OPC_BBIT132:
> +            tcg_gen_setcond_tl(TCG_COND_NE, bcond, t0, t1);
> +            goto not_likely;
> +            case OPC_BBIT0:
> +            tcg_gen_setcond_tl(TCG_COND_EQ, bcond, t0, t1);
> +            goto not_likely;
> +        case OPC_BBIT032:
> +            tcg_gen_setcond_tl(TCG_COND_EQ, bcond, t0, t1);
> +            goto not_likely;
>          case OPC_BNEL:
>              tcg_gen_setcond_tl(TCG_COND_NE, bcond, t0, t1);
>              MIPS_DEBUG("bnel %s, %s, " TARGET_FMT_lx,
> @@ -2983,7 +3408,44 @@ static void gen_compute_branch (DisasContext *ctx,
> uint32_t opc,
>      tcg_temp_free(t0);
>      tcg_temp_free(t1);
>  }
> +/*For cavium specific extract instructions*/
> +#if defined(TARGET_MIPS64)
> +static void gen_exts (CPUState *env,DisasContext *ctx, uint32_t opc, int
> rt,
> +                      int rs, int lsb, int msb)
> +{
> +    TCGv t0 = tcg_temp_new();
> +    TCGv t1 = tcg_temp_new();
> +    target_ulong mask;
> +    gen_load_gpr(t1, rs);
> +    switch (opc) {
> +    case OPC_EXTS:
> +        tcg_gen_shri_tl(t0, t1, lsb);
> +        tcg_gen_andi_tl(t0, t0, (1ULL << (msb + 1)) - 1);
> +        /* To sign extened the remaining bits according to
> +           the msb of the bit field */
> +        mask = 1ULL << msb;
> +        tcg_gen_andi_tl(t1, t0, mask);
> +        tcg_gen_addi_tl(t1, t1, -1);
> +        tcg_gen_not_i64(t1, t1);
> +        tcg_gen_or_tl(t0, t0, t1);
> +        gen_store_gpr(t0, rt);
> +        break;
> +    case OPC_EXTS32:
> +        tcg_gen_shri_tl(t0, t1, lsb + 32);
> +        tcg_gen_andi_tl(t0, t0, (1ULL << (msb + 1)) - 1);
> +        mask = 1ULL << msb;
> +        tcg_gen_andi_tl(t1, t0, mask);
> +        tcg_gen_addi_tl(t1, t1, -1);
> +        tcg_gen_not_i64(t1, t1);
> +        tcg_gen_or_tl(t0, t0, t1);
> +        gen_store_gpr(t0, rt);
> +        break;
> 
> +    }
> +    tcg_temp_free(t0);
> +    tcg_temp_free(t1);
> +}
> +#endif
>  /* special3 bitfield operations */
>  static void gen_bitops (DisasContext *ctx, uint32_t opc, int rt,
>                          int rs, int lsb, int msb)
> @@ -3063,6 +3525,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:
> @@ -11605,7 +12083,7 @@ static void decode_opc (CPUState *env, DisasContext
> *ctx, int *is_branch)
>      int32_t offset;
>      int rs, rt, rd, sa;
>      uint32_t op, op1, op2;
> -    int16_t imm;
> +    int16_t imm, imm10;
> 
>      /* make sure instructions are on a word boundary */
>      if (ctx->pc & 0x3) {
> @@ -11634,6 +12112,9 @@ static void decode_opc (CPUState *env, DisasContext
> *ctx, int *is_branch)
>      rd = (ctx->opcode >> 11) & 0x1f;
>      sa = (ctx->opcode >> 6) & 0x1f;
>      imm = (int16_t)ctx->opcode;
> +    /* 10 bit Immediate value For SEQI,SNEI */
> +    imm10 = (ctx->opcode >> 6) & 0x3ff;
> +
>      switch (op) {
>      case OPC_SPECIAL:
>          op1 = MASK_SPECIAL(ctx->opcode);
> @@ -11859,6 +12340,71 @@ 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_insn(env, ctx, ISA_MIPS3);
> +            check_mips_64(ctx);
> +            gen_muldiv(ctx, op1, rs, rt);
> +            tcg_gen_mov_tl(cpu_gpr[rd], cpu_LO[0]);
> +            break;
> +        case OPC_CINS:
> +            check_insn(env, ctx, ISA_MIPS64R2);
> +            check_mips_64(ctx);
> +            gen_bitops(ctx, op1, rt, rs, sa, rd);
> +            break;
> +        case OPC_CINS32:
> +            check_mips_64(ctx);
> +            gen_bitops(ctx, op1, rt, rs, sa, rd);
> +            break;
> +        case OPC_MTM0:
> +            check_mips_64(ctx);
> +            gen_LMI(env, ctx, op1, rs, rt, rd);
> +            break;
> +        case OPC_MTM1:
> +            check_mips_64(ctx);
> +            gen_LMI(env, ctx, op1, rs, rt, rd);
> +            break;
> +        case OPC_MTM2:
> +            check_mips_64(ctx);
> +            gen_LMI(env, ctx, op1, rs, rt, rd);
> +            break;
> +        case OPC_MTP0:
> +            check_mips_64(ctx);
> +            gen_LMI(env, ctx, op1, rs, rt, rd);
> +            break;
> +        case OPC_MTP1:
> +            check_mips_64(ctx);
> +            gen_LMI(env, ctx, op1, rs, rt, rd);
> +            break;
> +        case OPC_MTP2:
> +            check_mips_64(ctx);
> +            gen_LMI(env, ctx, op1, rs, rt, rd);
> +            break;
> +        case OPC_VMULU:
> +            check_mips_64(ctx);
> +            gen_LMI(env, ctx, op1, rs, rt, rd);
> +            break;
> +        case OPC_BADDU:
> +            gen_arith(env, ctx, op1, rd, rs, rt);
> +            break;
> +        case OPC_EXTS:
> +            check_mips_64(ctx);
> +            gen_exts(env, ctx, op1, rt, rs, sa, rd);
> +            break;
> +        case OPC_EXTS32:
> +            check_mips_64(ctx);
> +            gen_exts(env, ctx, op1, rt, rs, sa, rd);
> +            break;
> +        case OPC_SAA:
> +            gen_saa(env, ctx, op1, rt, rs);
> +            break;
> +        case OPC_SAAD:
> +            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);
> @@ -11878,13 +12424,24 @@ static void decode_opc (CPUState *env,
> DisasContext *ctx, int *is_branch)
>              break;
>          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:
>              check_insn(env, ctx, INSN_LOONGSON2F);
>              gen_loongson_integer(ctx, op1, rd, rs, rt);
>              break;
> +        case OPC_MULT_G_2F:
> +            if (!TARGET_OCTEON) {
> +                check_insn(env, ctx, INSN_LOONGSON2F);
> +                gen_loongson_integer(ctx, op1, rd, rs, rt);
> +            } else {
> +#if defined(TARGET_MIPS64)
> +                /* Cavium Specific vmm0 */
> +                check_mips_64(ctx);
> +                gen_LMI(env, ctx, op1, rs, rt, rd);
> +#endif
> +            }
> +            break;
>  #if defined(TARGET_MIPS64)
>          case OPC_DCLO:
>          case OPC_DCLZ:
> @@ -11892,7 +12449,6 @@ static void decode_opc (CPUState *env, DisasContext
> *ctx, int *is_branch)
>              check_mips_64(ctx);
>              gen_cl(ctx, op1, rd, rs);
>              break;
> -        case OPC_DMULT_G_2F:
>          case OPC_DMULTU_G_2F:
>          case OPC_DDIV_G_2F:
>          case OPC_DDIVU_G_2F:
> @@ -11901,6 +12457,39 @@ 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_DMULT_G_2F:
> +            if (!TARGET_OCTEON) {
> +                check_insn(env, ctx, INSN_LOONGSON2F);
> +                gen_loongson_integer(ctx, op1, rd, rs, rt);
> +            } else {
> +                /* Cavium Specific instruction v3mulu */
> +                check_mips_64(ctx);
> +                gen_LMI(env, ctx, op1, rs, rt, rd);
> +            }
> +            break;
> +        case OPC_SEQ:
> +            check_mips_64(ctx);
> +            gen_seqsne(ctx, op1, rd, rs, rt);
> +            break;
> +        case OPC_SNE:
> +            check_mips_64(ctx);
> +            gen_seqsne(ctx, op1, rd, rs, rt);
> +            break;
> +        case OPC_SEQI:
> +            check_mips_64(ctx);
> +            gen_set_imm(env, op1, rt, rs, imm10);
> +            break;
> +        case OPC_SNEI:
> +            check_mips_64(ctx);
> +            gen_set_imm(env, op1, rt, rs, imm10);
> +            break;
> +        case OPC_POP:
> +            insn_opc_pop(ctx, env, op1, rd, rs, rt);
> +            break;
> +        case OPC_DPOP:
> +            check_mips_64(ctx);
> +            insn_opc_dpop(ctx, env, op1, rd, rs, rt);
> +            break;
>  #endif
>          default:            /* Invalid */
>              MIPS_INVAL("special2");
> @@ -12192,10 +12781,32 @@ 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 TARGET_OCTEON is set these opcodes will belong to Cavium */
> +    case OPC_LWC2: /*BBIT0*/
> +        if(TARGET_OCTEON) {
> +            gen_compute_branch(ctx, op, 4, rs, rt, imm << 2);
> +            *is_branch = 1;
> +            break;
> +        }
> +    case OPC_LDC2: /*BBIT032*/
> +        if(TARGET_OCTEON) {
> +            gen_compute_branch(ctx, op, 4, rs, rt, imm << 2);
> +            *is_branch = 1;
> +            break;
> +        }
> +    case OPC_SWC2: /*BBIT1*/
> +        if(TARGET_OCTEON) {
> +            gen_compute_branch(ctx, op, 4, rs, rt, imm << 2);
> +            *is_branch = 1;
> +            break;
> +        }
> +    case OPC_SDC2: /*BBIT132*/
> +        if(TARGET_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);
> @@ -12584,6 +13195,18 @@ static void mips_tcg_init(void)
>      cpu_dspctrl = tcg_global_mem_new(TCG_AREG0,
>                                       offsetof(CPUState,
> active_tc.DSPControl),
>                                       "DSPControl");
> +    mpl0 = tcg_global_mem_new(TCG_AREG0,
> +                              offsetof(CPUState, Reg.MPL0), "MPL0");
> +    mpl1 = tcg_global_mem_new(TCG_AREG0,
> +                              offsetof(CPUState, Reg.MPL1), "MPL1");
> +    mpl2 = tcg_global_mem_new(TCG_AREG0,
> +                              offsetof(CPUState, Reg.MPL2), "MPL2");
> +    p0 = tcg_global_mem_new(TCG_AREG0,
> +                            offsetof(CPUState, Reg.P0), "P0");
> +    p1 = tcg_global_mem_new(TCG_AREG0,
> +                            offsetof(CPUState, Reg.P1), "P1");
> +    p2 = tcg_global_mem_new(TCG_AREG0,
> +                            offsetof(CPUState, Reg.P2), "P2");
>      bcond = tcg_global_mem_new(TCG_AREG0,
>                                 offsetof(CPUState, bcond), "bcond");
>      btarget = tcg_global_mem_new(TCG_AREG0,
> @@ -12607,6 +13230,18 @@ static void mips_tcg_init(void)
> 
>  #include "translate_init.c"
> 
> +#if defined(TARGET_MIPS64)
> +
> +static void set_cvmctl_register(CPUMIPSState *env)
> +{
> +    env->CvmCtlRegister.cvmctl = env->CvmCtlRegister.cvmctl
> +                                 ^ env->CvmCtlRegister.cvmctl;
> +    env->CvmCtlRegister.cvmctl =
> FUSE_START_BIT(env->CvmCtlRegister.cvmctl);
> +    env->CvmCtlRegister.cvmctl = KASUMI(env->CvmCtlRegister.cvmctl);
> +    env->CvmCtlRegister.cvmctl = IPPCI(env->CvmCtlRegister.cvmctl);
> +    env->CvmCtlRegister.cvmctl = IPTI(env->CvmCtlRegister.cvmctl);
> +}
> +#endif
>  CPUMIPSState *cpu_mips_init (const char *cpu_model)
>  {
>      CPUMIPSState *env;
> @@ -12619,6 +13254,10 @@ CPUMIPSState *cpu_mips_init (const char *cpu_model)
>      env->cpu_model = def;
>      env->cpu_model_str = cpu_model;
> 
> +#if defined(TARGET_MIPS64)
> +    /*Function for setting cvmctl register*/
> +    set_cvmctl_register(env);
> +#endif
>      cpu_exec_init(env);
>  #ifndef CONFIG_USER_ONLY
>      mmu_init(env, def);
> -- 
> 1.7.3.4
Nathan Froyd March 30, 2011, 4:38 p.m. UTC | #3
On Sat, Mar 26, 2011 at 11:58:37AM +0500, Khansa Butt wrote:
> Subject: [PATCH] MIPS64 user mode emulation in QEMU
>  This patch adds support for Cavium Network's
>  Octeon 57XX user mode instructions.  Octeon
>  57xx is based on MIPS64.  So this patch is
>  the first MIPS64 User Mode Emulation in QEMU
>  This is the team(Khansa Butt, Ehsan-ul-Haq, Abdul Qadeer, Abdul Waheed)
>  work of HPCNL Lab at KICS-UET Lahore.

Thanks for doing this.  As already noted, this patch should be split
into at least two patches: one to add Octeon-specific instructions in
target-mips/ and one adding the necessary linux-user bits.

> +extern int TARGET_OCTEON;

I don't think a global like this is the right way to go.  Perhaps the
elfload.c code should set a flag in image_info , which can then be used
to set a flag in CPUMIPSState later on.

If we must use a global variable, it should be declared in
target-mips/cpu.h.

> @@ -2013,7 +2024,8 @@ void cpu_loop(CPUMIPSState *env)
>                                   env->active_tc.gpr[5],
>                                   env->active_tc.gpr[6],
>                                   env->active_tc.gpr[7],
> -                                 arg5, arg6/*, arg7, arg8*/);
> +                                 env->active_tc.gpr[8],
> +                                 env->active_tc.gpr[9]/*, arg7, arg8*/);
>              }
>              if (ret == -TARGET_QEMU_ESIGRETURN) {
>                  /* Returning from a successful sigreturn syscall.

This change breaks O32 binaries; it needs to be done in a different way.

> diff --git a/linux-user/syscall.c b/linux-user/syscall.c
> index 499c4d7..47fef05 100644
> --- a/linux-user/syscall.c
> +++ b/linux-user/syscall.c
> @@ -7195,6 +7195,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long
> arg1,
>      case TARGET_NR_set_thread_area:
>  #if defined(TARGET_MIPS)
>        ((CPUMIPSState *) cpu_env)->tls_value = arg1;
> +       /*tls entry is moved to k0 so that this can be used later*/
> +      ((CPUMIPSState *) cpu_env)->active_tc.gpr[26] = arg1;
>        ret = 0;
>        break;
>  #elif defined(TARGET_CRIS)

I believe this is only correct for Octeon binaries; it's not how the
rest of the MIPS world works.  It therefore needs to be conditional on
Octeon-ness.

> --- a/target-mips/cpu.h
> +++ b/target-mips/cpu.h
> @@ -140,6 +140,20 @@ typedef struct mips_def_t mips_def_t;
>  #define MIPS_FPU_MAX 1
>  #define MIPS_DSP_ACC 4
> 
> +typedef struct cavium_mul cavium_mul;
> +struct cavium_mul {
> + target_ulong MPL0;
> + target_ulong MPL1;
> + target_ulong MPL2;
> + target_ulong P0;
> + target_ulong P1;
> + target_ulong P2;
> +};
> +typedef struct cvmctl_register cvmctl_register;
> +struct cvmctl_register {
> + target_ulong cvmctl;
> +};

The indentation here needs to be fixed.  I don't think there's any
reason why these need to be defined outside TCState, either.

> diff --git a/target-mips/translate.c b/target-mips/translate.c
> index cce77be..9c3d772 100644
> --- a/target-mips/translate.c
> +++ b/target-mips/translate.c
> @@ -36,6 +36,15 @@
>  #define GEN_HELPER 1
>  #include "helper.h"
> 
> +int TARGET_OCTEON;
> +#if defined(TARGET_MIPS64)
> +/*Macros for setting values of cvmctl registers*/
> +#define FUSE_START_BIT(cvmctl)(cvmctl | 0x80000000)
> +#define KASUMI(cvmctl)(cvmctl | 0x20000000)
> +#define IPPCI(cvmctl)(cvmctl | 0x380)
> +#define IPTI(cvmctl)(cvmctl | 0x70)
> +#endif

Please follow existing style; spaces between the comment and comment
markers (many examples in translate.c, not just here) and spaces between
the macro argument list and definition.

> @@ -779,7 +818,9 @@ static inline void gen_op_addr_add (DisasContext *ctx,
> TCGv ret, TCGv arg0, TCGv
>         See the MIPS64 PRA manual, section 4.10. */
>      if (((ctx->hflags & MIPS_HFLAG_KSU) == MIPS_HFLAG_UM) &&
>          !(ctx->hflags & MIPS_HFLAG_UX)) {
> -        tcg_gen_ext32s_i64(ret, ret);
> +        /*This function sign extend 32 bit value to 64 bit, was causing
> error
> +          when ld instruction came.Thats why it is commmented out*/
> +       /* tcg_gen_ext32s_i64(ret, ret);*/
>      }
>  #endif
>  }

Um, no.  If you needed to comment this out, you have a bug someplace
else.  Don't paper over the bug here.

> +        case OPC_VMULU:
> +        case OPC_V3MULU:

These two are large enough that they should be done as out-of-line
helpers.

Also, since all these new instructions are Octeon-specific, there should
be checks emitted to ensure that they produce appropriate errors when
non-Octeon hardware is being simulated, similar in style to
check_mips_64.

>  /* Arithmetic */
>  static void gen_arith (CPUState *env, DisasContext *ctx, uint32_t opc,
>                         int rd, int rs, int rt)
>  {
>      const char *opn = "arith";
> 
> +    target_ulong mask = 0xFF;

I don't think it's really necessary to have this, but if you feel it's
necessary, please move the declaration closer to the point of use.

> +#if defined(TARGET_MIPS64)
> +static void gen_seqsne (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();
> +    switch (opc) {
> +    case OPC_SEQ:
> +        {
> +            tcg_gen_xor_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]);
> +            gen_load_gpr(t0, rd);
> +            tcg_gen_setcondi_tl(TCG_COND_LTU, cpu_gpr[rd], t0, 1);
> +        }
> +        opn = "seq";
> +        break;

This looks like you are comparing rd with itself?

> +    case OPC_SNE:
> +        {
> +            tcg_gen_xor_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]);
> +            gen_load_gpr(t0, rd);
> +            gen_load_gpr(t1, 0);
> +            tcg_gen_setcond_tl(TCG_COND_LTU, cpu_gpr[rd], t1, t0);

You could use setcondi here by reversing the condition.

> +#if defined(TARGET_MIPS64)
> +static void insn_opc_pop (DisasContext *ctx, CPUState *env, uint32_t opc,
> +                          int rd, int rs, int rt)
> +static void insn_opc_dpop (DisasContext *ctx, CPUState *env, uint32_t opc,
> +                           int rd, int rs, int rt)

These should also be done as out-of-line helpers.

> @@ -2983,7 +3408,44 @@ static void gen_compute_branch (DisasContext *ctx,
> uint32_t opc,
>      tcg_temp_free(t0);
>      tcg_temp_free(t1);
>  }
> +/*For cavium specific extract instructions*/
> +#if defined(TARGET_MIPS64)
> +static void gen_exts (CPUState *env,DisasContext *ctx, uint32_t opc, int
> rt,
> +                      int rs, int lsb, int msb)
> +{
> +    TCGv t0 = tcg_temp_new();
> +    TCGv t1 = tcg_temp_new();
> +    target_ulong mask;
> +    gen_load_gpr(t1, rs);
> +    switch (opc) {
> +    case OPC_EXTS:
> +        tcg_gen_shri_tl(t0, t1, lsb);
> +        tcg_gen_andi_tl(t0, t0, (1ULL << (msb + 1)) - 1);
> +        /* To sign extened the remaining bits according to
> +           the msb of the bit field */
> +        mask = 1ULL << msb;
> +        tcg_gen_andi_tl(t1, t0, mask);
> +        tcg_gen_addi_tl(t1, t1, -1);
> +        tcg_gen_not_i64(t1, t1);
> +        tcg_gen_or_tl(t0, t0, t1);

You can use tcg_gen_orc_tl here and elsewhere.

-Nathan
Aurelien Jarno April 3, 2011, 10:03 p.m. UTC | #4
On Sat, Mar 26, 2011 at 11:58:37AM +0500, Khansa Butt wrote:
> From cd88be1263d0fc9802cd4dd358ed0299c0d106b0 Mon Sep 17 00:00:00 2001
> From: Khansa Butt & Ehsan-ul-Haq <khansa@kics.edu.pk>
> Date: Sat, 26 Mar 2011 11:53:11 +0500
> Subject: [PATCH] MIPS64 user mode emulation in QEMU
>  This patch adds support for Cavium Network's
>  Octeon 57XX user mode instructions.  Octeon
>  57xx is based on MIPS64.  So this patch is
>  the first MIPS64 User Mode Emulation in QEMU
>  This is the team(Khansa Butt, Ehsan-ul-Haq, Abdul Qadeer, Abdul Waheed)
>  work of HPCNL Lab at KICS-UET Lahore.
> 
> 
> Signed-off-by: Khansa Butt <khansa@kics.edu.pk>
> ---
>  configure                             |    1 +
>  default-configs/mips64-linux-user.mak |    1 +
>  exec.c                                |    1 +
>  linux-user/elfload.c                  |   15 +-
>  linux-user/main.c                     |   20 +-
>  linux-user/mips64/syscall.h           |    2 +
>  linux-user/signal.c                   |    3 +-
>  linux-user/syscall.c                  |    2 +
>  target-mips/cpu.h                     |   16 +
>  target-mips/translate.c               |  659
> ++++++++++++++++++++++++++++++++-
>  10 files changed, 704 insertions(+), 16 deletions(-)
>  create mode 100644 default-configs/mips64-linux-user.mak

Your patch actually contains 2 things
- Support for Cavium Octeon instructions
- Support for MIPS64 userland

The 2 things are independent and should be submitted as two different
patches.

Also the support for Octeon instruction should not depend on a global
variable, but should use the CPU features system already available.
Please have a look at target-mips/translate_init.c to see how it works.
Khansa Butt April 9, 2011, 8:36 a.m. UTC | #5
Please see inline comments highlighted in red.
I will be sending 2 updated patches for mips64 user mode emulation.

On Tue, Mar 29, 2011 at 1:55 PM, Riku Voipio <riku.voipio@iki.fi> wrote:

> Hi,
>
> First, do you have some instructions on howto build Octeon usermode
> 64bit binaries. Second, I think we would prefer that the patch was split
> to smaller patches. At least the target-mips changes should be a separate
> patch.
>
> Some more comments included inline between the code.
>
> On Sat, Mar 26, 2011 at 11:58:37AM +0500, Khansa Butt wrote:
> > >From cd88be1263d0fc9802cd4dd358ed0299c0d106b0 Mon Sep 17 00:00:00 2001
> > From: Khansa Butt & Ehsan-ul-Haq <khansa@kics.edu.pk>
> > Date: Sat, 26 Mar 2011 11:53:11 +0500
> > Subject: [PATCH] MIPS64 user mode emulation in QEMU
> >  This patch adds support for Cavium Network's
> >  Octeon 57XX user mode instructions.  Octeon
> >  57xx is based on MIPS64.  So this patch is
> >  the first MIPS64 User Mode Emulation in QEMU
> >  This is the team(Khansa Butt, Ehsan-ul-Haq, Abdul Qadeer, Abdul Waheed)
> >  work of HPCNL Lab at KICS-UET Lahore.
> >
> >
> > Signed-off-by: Khansa Butt <khansa@kics.edu.pk>
> > ---
> >  configure                             |    1 +
> >  default-configs/mips64-linux-user.mak |    1 +
> >  exec.c                                |    1 +
> >  linux-user/elfload.c                  |   15 +-
> >  linux-user/main.c                     |   20 +-
> >  linux-user/mips64/syscall.h           |    2 +
> >  linux-user/signal.c                   |    3 +-
> >  linux-user/syscall.c                  |    2 +
> >  target-mips/cpu.h                     |   16 +
> >  target-mips/translate.c               |  659
> > ++++++++++++++++++++++++++++++++-
> >  10 files changed, 704 insertions(+), 16 deletions(-)
> >  create mode 100644 default-configs/mips64-linux-user.mak
> >
> > diff --git a/configure b/configure
> > index 438219b..045a4ef 100755
> > --- a/configure
> > +++ b/configure
> > @@ -1011,6 +1011,7 @@ cris-linux-user \
> >  m68k-linux-user \
> >  microblaze-linux-user \
> >  mips-linux-user \
> > +mips64-linux-user \
> >  mipsel-linux-user \
> >  ppc-linux-user \
> >  ppc64-linux-user \
> > diff --git a/default-configs/mips64-linux-user.mak
> > b/default-configs/mips64-linux-user.mak
> > new file mode 100644
> > index 0000000..1598bfc
> > --- /dev/null
> > +++ b/default-configs/mips64-linux-user.mak
> > @@ -0,0 +1 @@
> > +# Default configuration for mips64-linux-user
> > diff --git a/exec.c b/exec.c
> > index 49c28b1..ee3f78e 100644
> > --- a/exec.c
> > +++ b/exec.c
> > @@ -2441,6 +2441,7 @@ int page_check_range(target_ulong start,
> target_ulong
> > len, int flags)
> >      for (addr = start, len = end - start;
> >           len != 0;
> >           len -= TARGET_PAGE_SIZE, addr += TARGET_PAGE_SIZE) {
> > +        addr  &= qemu_host_page_mask;
> >          p = page_find(addr >> TARGET_PAGE_BITS);
>
> Are you sure this will not generate ill effect on other target/host
> architecture
> combinations?
>
>
The line has been removed in order to avoid ill effects



> >          if( !p )
> >              return -1;
> > diff --git a/linux-user/elfload.c b/linux-user/elfload.c
> > index 33d776d..60fe85e 100644
> > --- a/linux-user/elfload.c
> > +++ b/linux-user/elfload.c
> > @@ -16,6 +16,8 @@
> >  #include "qemu.h"
> >  #include "disas.h"
> >
> > +extern int TARGET_OCTEON;
> > +
> >  #ifdef _ARCH_PPC64
> >  #undef ARCH_DLINFO
> >  #undef ELF_PLATFORM
> > @@ -25,6 +27,9 @@
> >  #undef ELF_ARCH
> >  #endif
> >
> > +#define EF_MIPS_MARCH 16711680
> > +#define E_MIPS_MACH_OCTEON 9109504
> > +
>
> please use hexadecimal values.
>
> >  #define ELF_OSABI   ELFOSABI_SYSV
> >
> >  /* from personality.h */
> > @@ -1313,7 +1318,7 @@ static void load_elf_image(const char *image_name,
> int
> > image_fd,
> >              vaddr_po = TARGET_ELF_PAGEOFFSET(vaddr);
> >              vaddr_ps = TARGET_ELF_PAGESTART(vaddr);
> >
> > -            error = target_mmap(vaddr_ps, eppnt->p_filesz + vaddr_po,
> > +            error = target_mmap(vaddr_ps, eppnt->p_memsz + vaddr_po,
> >                                  elf_prot, MAP_PRIVATE | MAP_FIXED,
> >                                  image_fd, eppnt->p_offset - vaddr_po);
> >              if (error == -1) {
> > @@ -1588,7 +1593,13 @@ int load_elf_binary(struct linux_binprm * bprm,
> > struct target_pt_regs * regs,
> >         If we do nothing, we'll have overwritten this when we re-use
> > bprm->buf
> >         when we load the interpreter.  */
> >      elf_ex = *(struct elfhdr *)bprm->buf;
> > -
> > +#if defined(TARGET_MIPS64)
> > +    if ((elf_ex.e_flags & EF_MIPS_MARCH) == E_MIPS_MACH_OCTEON) {
> > +        TARGET_OCTEON = 1;
> > +    } else {
> > +        TARGET_OCTEON = 0;
> > +    }
> > +#endif
> >      bprm->p = copy_elf_strings(1, &bprm->filename, bprm->page, bprm->p);
> >      bprm->p =
> copy_elf_strings(bprm->envc,bprm->envp,bprm->page,bprm->p);
> >      bprm->p =
> copy_elf_strings(bprm->argc,bprm->argv,bprm->page,bprm->p);
> > diff --git a/linux-user/main.c b/linux-user/main.c
> > index 0d627d6..8b4b90b 100644
> > --- a/linux-user/main.c
> > +++ b/linux-user/main.c
> > @@ -1937,10 +1937,16 @@ static int do_store_exclusive(CPUMIPSState *env)
> >      int d;
> >
> >      addr = env->lladdr;
> > +    /* 64 bit address is converted to 32 bit value so that a valid
> > +    * l1_map value can be accessed. This thing is needed for target
> > +    * mips64 and host 32 bit x86
> > +    */
> > +    addr &= qemu_host_page_mask;
>
> same as earlier.
>

The above line is changed with following code snippet
#if defined(TARGET_MIPS64)
+/* For MIPS64 on 32 bit host there is a need to make
+* the page accessible to which the above 'addr' is belonged */
+#if HOST_LONG_BITS == 32
+    int flag = PAGE_VALID | PAGE_READ | PAGE_WRITE | PAGE_WRITE_ORG;
+    page_set_flags(addr, addr + 4096, flag);
+#endif
+#endif



>
> >      page_addr = addr & TARGET_PAGE_MASK;
> >      start_exclusive();
> >      mmap_lock();
> >      flags = page_get_flags(page_addr);
> > +    addr = env->lladdr;
> >      if ((flags & PAGE_READ) == 0) {
> >          segv = 1;
> >      } else {
> > @@ -1978,7 +1984,8 @@ static int do_store_exclusive(CPUMIPSState *env)
> >  void cpu_loop(CPUMIPSState *env)
> >  {
> >      target_siginfo_t info;
> > -    int trapnr, ret;
> > +    int trapnr;
> > +    abi_long ret;
> >      unsigned int syscall_num;
> >
> >      for(;;) {
> > @@ -1987,7 +1994,11 @@ void cpu_loop(CPUMIPSState *env)
> >          cpu_exec_end(env);
> >          switch(trapnr) {
> >          case EXCP_SYSCALL:
> > +#if defined(TARGET_MIPS64)
> > +            syscall_num = env->active_tc.gpr[2] - 5000;
> > +#else
> >              syscall_num = env->active_tc.gpr[2] - 4000;
> > +#endif
> >              env->active_tc.PC += 4;
> >              if (syscall_num >= sizeof(mips_syscall_args)) {
> >                  ret = -ENOSYS;
> > @@ -2013,7 +2024,8 @@ void cpu_loop(CPUMIPSState *env)
> >                                   env->active_tc.gpr[5],
> >                                   env->active_tc.gpr[6],
> >                                   env->active_tc.gpr[7],
> > -                                 arg5, arg6/*, arg7, arg8*/);
> > +                                 env->active_tc.gpr[8],
> > +                                 env->active_tc.gpr[9]/*, arg7, arg8*/);
> >              }
> >              if (ret == -TARGET_QEMU_ESIGRETURN) {
> >                  /* Returning from a successful sigreturn syscall.
> > @@ -2926,7 +2938,9 @@ int main(int argc, char **argv, char **envp)
> >  #endif
> >  #elif defined(TARGET_MIPS)
> >  #if defined(TARGET_ABI_MIPSN32) || defined(TARGET_ABI_MIPSN64)
> > -        cpu_model = "20Kc";
> > +        /* we use this model so that we can decode MIPS64r2
> > +           reserved instruction */
> > +        cpu_model = "MIPS64R2-generic";
> >  #else
> >          cpu_model = "24Kf";
> >  #endif
> > diff --git a/linux-user/mips64/syscall.h b/linux-user/mips64/syscall.h
> > index 668a2b9..1395e61 100644
> > --- a/linux-user/mips64/syscall.h
> > +++ b/linux-user/mips64/syscall.h
> > @@ -217,5 +217,7 @@ struct target_pt_regs {
> >  #define TARGET_ENOTRECOVERABLE 166     /* State not recoverable */
> >
> >
> > +/* Nasty hack: define a fake errno value for use by sigreturn.  */
> > +#define TARGET_QEMU_ESIGRETURN 255
> >
> >  #define UNAME_MACHINE "mips64"
> > diff --git a/linux-user/signal.c b/linux-user/signal.c
> > index c846b8c..114116c 100644
> > --- a/linux-user/signal.c
> > +++ b/linux-user/signal.c
> > @@ -2410,7 +2410,8 @@ void sparc64_get_context(CPUSPARCState *env)
> >  #endif
> >  #elif defined(TARGET_ABI_MIPSN64)
> >
> > -# warning signal handling not implemented
> > +/*this line is commented out to avoid compile time error*/
> > +/*# warning signal handling not implemented*/
> >
> >  static void setup_frame(int sig, struct target_sigaction *ka,
> >   target_sigset_t *set, CPUState *env)
> > diff --git a/linux-user/syscall.c b/linux-user/syscall.c
> > index 499c4d7..47fef05 100644
> > --- a/linux-user/syscall.c
> > +++ b/linux-user/syscall.c
> > @@ -7195,6 +7195,8 @@ abi_long do_syscall(void *cpu_env, int num,
> abi_long
> > arg1,
> >      case TARGET_NR_set_thread_area:
> >  #if defined(TARGET_MIPS)
> >        ((CPUMIPSState *) cpu_env)->tls_value = arg1;
> > +       /*tls entry is moved to k0 so that this can be used later*/
> > +      ((CPUMIPSState *) cpu_env)->active_tc.gpr[26] = arg1;
>
> Does this affect the non-octeon mips ?
>


The above thing has been made Octeon specific.


>
> >        ret = 0;
> >        break;
> >  #elif defined(TARGET_CRIS)
>
> And someone else will need to comment the TCG changes.
>
> > diff --git a/target-mips/cpu.h b/target-mips/cpu.h
> > index 2419aa9..59bcc0f 100644
> > --- a/target-mips/cpu.h
> > +++ b/target-mips/cpu.h
> > @@ -140,6 +140,20 @@ typedef struct mips_def_t mips_def_t;
> >  #define MIPS_FPU_MAX 1
> >  #define MIPS_DSP_ACC 4
> >
> > +typedef struct cavium_mul cavium_mul;
> > +struct cavium_mul {
> > + target_ulong MPL0;
> > + target_ulong MPL1;
> > + target_ulong MPL2;
> > + target_ulong P0;
> > + target_ulong P1;
> > + target_ulong P2;
> > +};
> > +typedef struct cvmctl_register cvmctl_register;
> > +struct cvmctl_register {
> > + target_ulong cvmctl;
> > +};
> > +
> >  typedef struct TCState TCState;
> >  struct TCState {
> >      target_ulong gpr[32];
> > @@ -178,6 +192,8 @@ struct CPUMIPSState {
> >      TCState active_tc;
> >      CPUMIPSFPUContext active_fpu;
> >
> > +    cavium_mul Reg;
> > +    cvmctl_register CvmCtlRegister;
> >      uint32_t current_tc;
> >      uint32_t current_fpu;
> >
> > diff --git a/target-mips/translate.c b/target-mips/translate.c
> > index cce77be..9c3d772 100644
> > --- a/target-mips/translate.c
> > +++ b/target-mips/translate.c
> > @@ -36,6 +36,15 @@
> >  #define GEN_HELPER 1
> >  #include "helper.h"
> >
> > +int TARGET_OCTEON;
> > +#if defined(TARGET_MIPS64)
> > +/*Macros for setting values of cvmctl registers*/
> > +#define FUSE_START_BIT(cvmctl)(cvmctl | 0x80000000)
> > +#define KASUMI(cvmctl)(cvmctl | 0x20000000)
> > +#define IPPCI(cvmctl)(cvmctl | 0x380)
> > +#define IPTI(cvmctl)(cvmctl | 0x70)
> > +#endif
> > +
> >  //#define MIPS_DEBUG_DISAS
> >  //#define MIPS_DEBUG_SIGN_EXTENSIONS
> >
> > @@ -70,6 +79,11 @@ enum {
> >      OPC_JAL      = (0x03 << 26),
> >      OPC_JALS     = OPC_JAL | 0x5,
> >      OPC_BEQ      = (0x04 << 26),  /* Unconditional if rs = rt = 0 (B) */
> > +    /* Cavium Specific */
> > +    OPC_BBIT1    = (0x3a << 26),  /*jump on bit set, cavium specific*/
> > +    OPC_BBIT132  = (0x3e << 26),  /*jump on bit set(one of the upper 32
> > bits)*/
> > +    OPC_BBIT0    = (0x32 << 26),  /*jump on bit clear, cavium specific*/
> > +    OPC_BBIT032  = (0x36 << 26),  /*jump on bit set(one of the upper 32
> > bits)*/
> >      OPC_BEQL     = (0x14 << 26),
> >      OPC_BNE      = (0x05 << 26),
> >      OPC_BNEL     = (0x15 << 26),
> > @@ -265,6 +279,31 @@ enum {
> >      OPC_MADD     = 0x00 | OPC_SPECIAL2,
> >      OPC_MADDU    = 0x01 | OPC_SPECIAL2,
> >      OPC_MUL      = 0x02 | 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,
> > +/**************************************/
> >      OPC_MSUB     = 0x04 | OPC_SPECIAL2,
> >      OPC_MSUBU    = 0x05 | OPC_SPECIAL2,
> >      /* Loongson 2F */
> > @@ -483,7 +522,7 @@ enum {
> >  static TCGv_ptr cpu_env;
> >  static TCGv cpu_gpr[32], cpu_PC;
> >  static TCGv cpu_HI[MIPS_DSP_ACC], cpu_LO[MIPS_DSP_ACC],
> > cpu_ACX[MIPS_DSP_ACC];
> > -static TCGv cpu_dspctrl, btarget, bcond;
> > +static TCGv cpu_dspctrl, btarget, bcond, mpl0, mpl1, mpl2, p0, p1, p2;
> >  static TCGv_i32 hflags;
> >  static TCGv_i32 fpu_fcr0, fpu_fcr31;
> >
> > @@ -779,7 +818,9 @@ static inline void gen_op_addr_add (DisasContext
> *ctx,
> > TCGv ret, TCGv arg0, TCGv
> >         See the MIPS64 PRA manual, section 4.10. */
> >      if (((ctx->hflags & MIPS_HFLAG_KSU) == MIPS_HFLAG_UM) &&
> >          !(ctx->hflags & MIPS_HFLAG_UX)) {
> > -        tcg_gen_ext32s_i64(ret, ret);
> > +        /*This function sign extend 32 bit value to 64 bit, was causing
> > error
> > +          when ld instruction came.Thats why it is commmented out*/
> > +       /* tcg_gen_ext32s_i64(ret, ret);*/
> >      }
> >  #endif
> >  }
> > @@ -1419,7 +1460,33 @@ static void gen_arith_imm (CPUState *env,
> > DisasContext *ctx, uint32_t opc,
> >      (void)opn; /* avoid a compiler warning */
> >      MIPS_DEBUG("%s %s, %s, " TARGET_FMT_lx, opn, regnames[rt],
> > regnames[rs], uimm);
> >  }
> > -
> > +#if defined(TARGET_MIPS64)
> > +/*set on equal immidiate/seton not equal immidiate*/
> > +static void gen_set_imm(CPUState *env, uint32_t opc, int rt, int rs,
> > int16_t imm)
> > +{
> > +    target_ulong uimm;
> > +    TCGv t0, t1;
> > +    const char *opn = "imm set";
> > +    uimm = (uint16_t)imm;
> > +    t0 = tcg_temp_new();
> > +    t1 = tcg_temp_new();
> > +    switch (opc) {
> > +    case OPC_SEQI:
> > +        tcg_gen_xori_tl(cpu_gpr[rt], cpu_gpr[rs], uimm);
> > +        gen_load_gpr(t0, rt);
> > +        tcg_gen_setcondi_tl(TCG_COND_LTU, cpu_gpr[rt], t0, 1);
> > +        opn = "seqi";
> > +        break;
> > +    case OPC_SNEI:
> > +        tcg_gen_xori_tl(cpu_gpr[rt], cpu_gpr[rs], uimm);
> > +        gen_load_gpr(t0, rt);
> > +        gen_load_gpr(t1, 0);
> > +        tcg_gen_setcond_tl(TCG_COND_LTU, cpu_gpr[rt], t1, t0);
> > +        opn = "snei";
> > +        break;
> > +    }
> > +}
> > +#endif
> >  /* Logic with immediate operand */
> >  static void gen_logic_imm (CPUState *env, uint32_t opc, int rt, int rs,
> > int16_t imm)
> >  {
> > @@ -1583,13 +1650,196 @@ static void gen_shift_imm(CPUState *env,
> > DisasContext *ctx, uint32_t opc,
> >      MIPS_DEBUG("%s %s, %s, " TARGET_FMT_lx, opn, regnames[rt],
> > regnames[rs], uimm);
> >      tcg_temp_free(t0);
> >  }
> > +#if defined(TARGET_MIPS64)
> > +/* Addition and carry detection*/
> > +static void gen_addc (TCGv arg1, TCGv arg2, TCGv res, TCGv c)
> > +{
> > +    tcg_gen_add_tl(res, arg1, arg2);
> > +    tcg_gen_setcond_tl(TCG_COND_LTU, c, res, arg1);
> > +}
> > +static void gen_LMI (CPUMIPSState *env, DisasContext *ctx, uint32_t opc,
> > +                 int rs, int rt, int rd)
> > +{
> > +    const char *opn = "LMI";
> > +    TCGv t0, t1;
> > +    int nomul = env->CvmCtlRegister.cvmctl & 0x8000000;
> > +    if (!nomul) {
> > +        switch (opc) {
> > +        case OPC_MTM0:
> > +            tcg_gen_mov_tl(mpl0, cpu_gpr[rs]);
> > +            tcg_gen_movi_tl(p0, 0);
> > +            tcg_gen_movi_tl(p1, 0);
> > +            tcg_gen_movi_tl(p2, 0);
> > +            opn = "mtm0";
> > +            break;
> > +        case OPC_MTM1:
> > +            tcg_gen_mov_tl(mpl1, cpu_gpr[rs]);
> > +            tcg_gen_movi_tl(p0, 0);
> > +            tcg_gen_movi_tl(p1, 0);
> > +            tcg_gen_movi_tl(p2, 0);
> > +            opn = "mtm1";
> > +            break;
> > +        case OPC_MTM2:
> > +            tcg_gen_mov_tl(mpl2, cpu_gpr[rs]);
> > +            tcg_gen_movi_tl(p0, 0);
> > +            tcg_gen_movi_tl(p1, 0);
> > +            tcg_gen_movi_tl(p2, 0);
> > +            opn = "mtm2";
> > +            break;
> > +        case OPC_MTP0:
> > +            tcg_gen_mov_tl(p0, cpu_gpr[rs]);
> > +            opn = "mtp0";
> > +            break;
> > +        case OPC_MTP1:
> > +            tcg_gen_mov_tl(p1, cpu_gpr[rs]);
> > +            opn = "mtp1";
> > +            break;
> > +        case OPC_MTP2:
> > +            tcg_gen_mov_tl(p2, cpu_gpr[rs]);
> > +            opn = "mtp2";
> > +            break;
> > +        case OPC_VMM0:
> > +            t0 = tcg_temp_new();
> > +            t1 = tcg_temp_new();
> > +            gen_load_gpr(t1, rs);
> > +            gen_helper_dmultu(t1, mpl0);
> > +            gen_load_gpr(t0, rt);
> > +            tcg_gen_add_tl(t0, t0, cpu_LO[0]);
> > +            tcg_gen_add_tl(t0, t0, p0);
> > +            gen_store_gpr(t0, rd);
> > +            tcg_gen_mov_tl(mpl0, cpu_gpr[rd]);
> > +            tcg_gen_movi_tl(p0, 0);
> > +            tcg_gen_movi_tl(p1, 0);
> > +            tcg_gen_movi_tl(p2, 0);
> > +            tcg_temp_free(t0);
> > +            tcg_temp_free(t1);
> > +            opn = "vmm0";
> > +            break;
> > +        case OPC_VMULU:
> > +            {
> > +                TCGv t2, c;
> > +                t0 = tcg_temp_new();
> > +                t1 = tcg_temp_new();
> > +                t2 = tcg_temp_new();
> > +                c = tcg_temp_new();
> > +                gen_load_gpr(t1, rs);
> > +                gen_load_gpr(t2, rt);
> > +                gen_helper_dmultu(t1, mpl0);
> > +                tcg_gen_mov_tl(t0, cpu_LO[0]);
> > +                /*if carry comes due to addition of rt and LO register,
> > +                 * this carry should be added to HI register.
> > +                 */
> > +                gen_addc(t0, t2, t1, c);
> >
> > +                tcg_gen_add_tl(cpu_HI[0], cpu_HI[0], c);
> > +                /* t0 = t1 + p0 where t1 = LO+rt*/
> > +                gen_addc(t1, p0, t0, c);
> > +                tcg_gen_add_tl(cpu_HI[0], cpu_HI[0], c);
> > +
> > +                tcg_gen_mov_tl(cpu_gpr[rd], t0);
> > +                tcg_gen_mov_tl(p0, cpu_HI[0]);
> > +                tcg_temp_free(t0);
> > +                tcg_temp_free(t1);
> > +                tcg_temp_free(t2);
> > +                opn = "vmulu";
> > +                break;
> > +            }
> > +        case OPC_V3MULU:
> > +            {
> > +                TCGv temp[4];
> > +                TCGv c;
> > +                TCGv trs, trt, tc1, tc2, tc3;
> > +                temp[0] = tcg_temp_new();
> > +                temp[1] = tcg_temp_new();
> > +                temp[2] = tcg_temp_new();
> > +                temp[3] = tcg_temp_new();
> > +                trs = tcg_temp_new();
> > +                trt = tcg_temp_new();
> > +                tc1 = tcg_temp_new();
> > +                tc2 = tcg_temp_new();
> > +                tc3 = tcg_temp_new();
> > +                c = tcg_temp_new();
> > +                gen_load_gpr(trs, rs);
> > +                gen_load_gpr(trt, rt);
> > +                /* rs × (MPL2 || MPL1 || MPL0) (192X64 bit
> multiplication)
> > */
> > +                gen_helper_dmultu(trs, mpl0);
> > +                tcg_gen_mov_tl(temp[0], cpu_LO[0]);
> > +                tcg_gen_mov_tl(temp[1], cpu_HI[0]);
> > +
> > +                gen_helper_dmultu(trs, mpl1);
> > +                tcg_gen_mov_tl(temp[2], cpu_HI[0]);
> > +                gen_addc(cpu_LO[0], temp[1], tc1, tc2);
> > +                gen_addc(temp[2], tc2, tc3, c);
> > +                tcg_gen_mov_tl(temp[1], tc1);
> > +                tcg_gen_mov_tl(temp[2], tc3);
> > +                tcg_gen_mov_tl(temp[3], c);
> > +
> > +                gen_helper_dmultu(trs, mpl2);
> > +                tcg_gen_add_tl(temp[3], temp[3], cpu_HI[0]);
> > +                gen_addc(cpu_LO[0], temp[2], tc1, tc2);
> > +                tcg_gen_mov_tl(temp[2], tc1);
> > +                tcg_gen_add_tl(temp[3], temp[3], tc2);
> > +                /* Addition of rt in 256 bit result
> > +                  (t3 t2 t1 t0 contain result) */
> > +                gen_addc(temp[0], trt, tc1, c);
> > +                tcg_gen_mov_tl(temp[0], tc1);
> > +                gen_addc(temp[1], c, tc1, tc2);
> > +                tcg_gen_mov_tl(temp[1], tc1);
> > +                gen_addc(temp[2], tc2, tc1, c);
> > +                tcg_gen_mov_tl(temp[2], tc1);
> > +                tcg_gen_add_tl(temp[3], temp[3], c);
> > +                /* Addition of p2 p1 p0 in 256 bit result */
> > +                gen_addc(temp[0], p0, tc1, c);
> > +                tcg_gen_mov_tl(temp[0], tc1);
> > +                gen_addc(temp[1], c, tc1, tc2);
> > +                tcg_gen_mov_tl(temp[1], tc1);
> > +                gen_addc(temp[2], tc2, tc1, c);
> > +                tcg_gen_mov_tl(temp[2], tc1);
> > +                tcg_gen_add_tl(temp[3], temp[3], c);
> > +
> > +                gen_addc(temp[1], p1, tc1, c);
> > +                tcg_gen_mov_tl(temp[1], tc1);
> > +                gen_addc(temp[2], c, tc1, tc2);
> > +                tcg_gen_mov_tl(temp[2], tc1);
> > +                tcg_gen_add_tl(temp[3], temp[3], tc2);
> > +
> > +                gen_addc(temp[2], p2, tc1, c);
> > +                tcg_gen_mov_tl(temp[2], tc1);
> > +                tcg_gen_add_tl(temp[3], temp[3], c);
> > +                /* final step */
> > +                tcg_gen_mov_tl(cpu_gpr[rd], temp[0]);
> > +                tcg_gen_mov_tl(p0, temp[1]);
> > +                tcg_gen_mov_tl(p1, temp[2]);
> > +                tcg_gen_mov_tl(p2, temp[3]);
> > +                tcg_temp_free(temp[0]);
> > +                tcg_temp_free(temp[1]);
> > +                tcg_temp_free(temp[2]);
> > +                tcg_temp_free(temp[3]);
> > +                tcg_temp_free(trs);
> > +                tcg_temp_free(trt);
> > +                tcg_temp_free(tc1);
> > +                tcg_temp_free(tc2);
> > +                tcg_temp_free(tc3);
> > +                tcg_temp_free(c);
> > +                opn = "v3mulu";
> > +                break;
> > +            }
> > +        }
> > +
> > +    } else {
> > +        generate_exception(ctx, EXCP_RI);
> > +    }
> > +}
> > +
> > +
> > +#endif
> >  /* Arithmetic */
> >  static void gen_arith (CPUState *env, DisasContext *ctx, uint32_t opc,
> >                         int rd, int rs, int rt)
> >  {
> >      const char *opn = "arith";
> >
> > +    target_ulong mask = 0xFF;
> >      if (rd == 0 && opc != OPC_ADD && opc != OPC_SUB
> >         && opc != OPC_DADD && opc != OPC_DSUB) {
> >          /* If no destination, treat it as a NOP.
> > @@ -1637,6 +1887,22 @@ 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();
> > +            TCGv t2 = tcg_temp_new();
> > +            gen_load_gpr(t1, rs);
> > +            gen_load_gpr(t2, rt);
> > +            tcg_gen_andi_tl(t1, t1, mask);
> > +            tcg_gen_andi_tl(t2, t2, mask);
> > +            tcg_gen_add_tl(t0, t1, t2);
> > +            tcg_gen_andi_tl(t0, t0, mask);
> > +            gen_store_gpr(t0, rd);
> > +        }
> > +
> > +       opn = "baddu";
> > +       break;
> >      case OPC_SUB:
> >          {
> >              TCGv t0 = tcg_temp_local_new();
> > @@ -2013,7 +2279,74 @@ static void gen_HILO (DisasContext *ctx, uint32_t
> > opc, int reg)
> >      (void)opn; /* avoid a compiler warning */
> >      MIPS_DEBUG("%s %s", opn, regnames[reg]);
> >  }
> > +#if defined(TARGET_MIPS64)
> > +static void gen_seqsne (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();
> > +    switch (opc) {
> > +    case OPC_SEQ:
> > +        {
> > +            tcg_gen_xor_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]);
> > +            gen_load_gpr(t0, rd);
> > +            tcg_gen_setcondi_tl(TCG_COND_LTU, cpu_gpr[rd], t0, 1);
> > +        }
> > +        opn = "seq";
> > +        break;
> > +    case OPC_SNE:
> > +        {
> > +            tcg_gen_xor_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]);
> > +            gen_load_gpr(t0, rd);
> > +            gen_load_gpr(t1, 0);
> > +            tcg_gen_setcond_tl(TCG_COND_LTU, cpu_gpr[rd], t1, t0);
> > +        }
> > +        opn = "sne";
> > +        break;
> > +    default:
> > +        MIPS_INVAL(opn);
> > +        generate_exception(ctx, EXCP_RI);
> > +        goto out;
> > +    }
> > +out:
> > +        tcg_temp_free(t0);
> > +        tcg_temp_free(t1);
> >
> > +}
> > +
> > +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_lw(temp, t0, ctx);
> > +        tcg_gen_add_tl(temp, temp, t1);
> > +        op_st_sw(temp, t0, ctx);
> > +        opn = "saa";
> > +        break;
> > +    case OPC_SAAD:
> > +        save_cpu_state(ctx, 0);
> > +        op_ld_ld(temp, t0, ctx);
> > +        tcg_gen_add_tl(temp, temp, t1);
> > +        op_st_sd(temp, t0, ctx);
> > +        opn = "saad";
> > +        break;
> > +    }
> > +
> > +    tcg_temp_free(t0);
> > +    tcg_temp_free(t1);
> > +}
> > +#endif
> >  static void gen_muldiv (DisasContext *ctx, uint32_t opc,
> >                          int rs, int rt)
> >  {
> > @@ -2149,6 +2482,10 @@ static void gen_muldiv (DisasContext *ctx,
> uint32_t
> > opc,
> >          gen_helper_dmult(t0, t1);
> >          opn = "dmult";
> >          break;
> > +    case OPC_DMUL:
> > +        gen_helper_dmult(t0, t1);
> > +        opn = "dmul";
> > +        break;
> >      case OPC_DMULTU:
> >          gen_helper_dmultu(t0, t1);
> >          opn = "dmultu";
> > @@ -2368,7 +2705,49 @@ static void gen_cl (DisasContext *ctx, uint32_t
> opc,
> >      MIPS_DEBUG("%s %s, %s", opn, regnames[rd], regnames[rs]);
> >      tcg_temp_free(t0);
> >  }
> > +#if defined(TARGET_MIPS64)
> > +static void insn_opc_pop (DisasContext *ctx, CPUState *env, uint32_t
> opc,
> > +                          int rd, int rs, int rt)
> > +{
> > +    TCGv num = tcg_temp_new();
> > +    TCGv res = tcg_temp_new();
> > +    target_ulong maskb = 1;
> > +    gen_load_gpr(num, rs);
> > +    TCGv ones=tcg_temp_new();
> > +    gen_load_gpr(ones, 0);
> > +    int x=1;
> > +    tcg_gen_andi_tl(res, num, maskb);
> > +    tcg_gen_add_tl(ones,ones, res);
> > +    while (x <= 31) {
> > +        tcg_gen_shri_i64(num, num, 1);
> > +        tcg_gen_andi_tl(res, num, maskb);
> > +        tcg_gen_add_tl(ones, ones, res);
> > +        x++;
> > +    }
> > +    gen_store_gpr(ones, rd);
> > +}
> > +static void insn_opc_dpop (DisasContext *ctx, CPUState *env, uint32_t
> opc,
> > +                           int rd, int rs, int rt)
> > +{
> > +    TCGv num, res, ones;
> > +    num = tcg_temp_new();
> > +    res = tcg_temp_new();
> > +    ones = tcg_temp_new();
> > +    target_ulong maskb = 1;
> > +    gen_load_gpr(num, rs);
> > +    int x = 1;
> > +    tcg_gen_andi_tl(res, num, maskb);
> > +    tcg_gen_mov_tl(ones, res);
> >
> > +    while (x <= 63) {
> > +        tcg_gen_shri_i64(num, num, 1);
> > +        tcg_gen_andi_tl(res, num, maskb);
> > +        tcg_gen_add_tl(ones, ones, res);
> > +        x++;
> > +    }
> > +    gen_store_gpr(ones, rd);
> > +}
> > +#endif
> >  /* Godson integer instructions */
> >  static void gen_loongson_integer (DisasContext *ctx, uint32_t opc,
> >                                  int rd, int rs, int rt)
> > @@ -2705,6 +3084,7 @@ static void gen_compute_branch (DisasContext *ctx,
> > uint32_t opc,
> >      target_ulong btgt = -1;
> >      int blink = 0;
> >      int bcond_compute = 0;
> > +    target_ulong maskb; /* Used in BBIT0 and BBIT1*/
> >      TCGv t0 = tcg_temp_new();
> >      TCGv t1 = tcg_temp_new();
> >
> > @@ -2730,6 +3110,39 @@ static void gen_compute_branch (DisasContext *ctx,
> > uint32_t opc,
> >          }
> >          btgt = ctx->pc + insn_bytes + offset;
> >          break;
> > +    case OPC_BBIT1:
> > +        gen_load_gpr(t0, rs);
> > +        gen_load_gpr(t1, 0);
> > +        maskb = 1ULL << rt;
> > +        tcg_gen_andi_tl(t0, t0, maskb);
> > +        bcond_compute = 1;
> > +        btgt = ctx->pc + insn_bytes + offset;
> > +        break;
> > +    case OPC_BBIT132:
> > +        gen_load_gpr(t0, rs);
> > +        gen_load_gpr(t1, 0);
> > +        maskb = 1ULL << (rt + 32);
> > +        tcg_gen_andi_tl(t0, t0, maskb);
> > +        bcond_compute = 1;
> > +        btgt = ctx->pc + insn_bytes + offset;
> > +        break;
> > +    case OPC_BBIT0:
> > +        gen_load_gpr(t0, rs);
> > +        gen_load_gpr(t1, 0);
> > +        maskb = 1ULL << rt;
> > +        tcg_gen_andi_tl(t0, t0, maskb);
> > +        bcond_compute = 1;
> > +        btgt = ctx->pc + insn_bytes + offset;
> > +        break;
> > +    case OPC_BBIT032:
> > +        gen_load_gpr(t0, rs);
> > +        gen_load_gpr(t1, 0);
> > +        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:
> > @@ -2888,6 +3301,18 @@ 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:
> > +            tcg_gen_setcond_tl(TCG_COND_NE, bcond, t0, t1);
> > +            goto not_likely;
> > +        case OPC_BBIT132:
> > +            tcg_gen_setcond_tl(TCG_COND_NE, bcond, t0, t1);
> > +            goto not_likely;
> > +            case OPC_BBIT0:
> > +            tcg_gen_setcond_tl(TCG_COND_EQ, bcond, t0, t1);
> > +            goto not_likely;
> > +        case OPC_BBIT032:
> > +            tcg_gen_setcond_tl(TCG_COND_EQ, bcond, t0, t1);
> > +            goto not_likely;
> >          case OPC_BNEL:
> >              tcg_gen_setcond_tl(TCG_COND_NE, bcond, t0, t1);
> >              MIPS_DEBUG("bnel %s, %s, " TARGET_FMT_lx,
> > @@ -2983,7 +3408,44 @@ static void gen_compute_branch (DisasContext *ctx,
> > uint32_t opc,
> >      tcg_temp_free(t0);
> >      tcg_temp_free(t1);
> >  }
> > +/*For cavium specific extract instructions*/
> > +#if defined(TARGET_MIPS64)
> > +static void gen_exts (CPUState *env,DisasContext *ctx, uint32_t opc, int
> > rt,
> > +                      int rs, int lsb, int msb)
> > +{
> > +    TCGv t0 = tcg_temp_new();
> > +    TCGv t1 = tcg_temp_new();
> > +    target_ulong mask;
> > +    gen_load_gpr(t1, rs);
> > +    switch (opc) {
> > +    case OPC_EXTS:
> > +        tcg_gen_shri_tl(t0, t1, lsb);
> > +        tcg_gen_andi_tl(t0, t0, (1ULL << (msb + 1)) - 1);
> > +        /* To sign extened the remaining bits according to
> > +           the msb of the bit field */
> > +        mask = 1ULL << msb;
> > +        tcg_gen_andi_tl(t1, t0, mask);
> > +        tcg_gen_addi_tl(t1, t1, -1);
> > +        tcg_gen_not_i64(t1, t1);
> > +        tcg_gen_or_tl(t0, t0, t1);
> > +        gen_store_gpr(t0, rt);
> > +        break;
> > +    case OPC_EXTS32:
> > +        tcg_gen_shri_tl(t0, t1, lsb + 32);
> > +        tcg_gen_andi_tl(t0, t0, (1ULL << (msb + 1)) - 1);
> > +        mask = 1ULL << msb;
> > +        tcg_gen_andi_tl(t1, t0, mask);
> > +        tcg_gen_addi_tl(t1, t1, -1);
> > +        tcg_gen_not_i64(t1, t1);
> > +        tcg_gen_or_tl(t0, t0, t1);
> > +        gen_store_gpr(t0, rt);
> > +        break;
> >
> > +    }
> > +    tcg_temp_free(t0);
> > +    tcg_temp_free(t1);
> > +}
> > +#endif
> >  /* special3 bitfield operations */
> >  static void gen_bitops (DisasContext *ctx, uint32_t opc, int rt,
> >                          int rs, int lsb, int msb)
> > @@ -3063,6 +3525,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:
> > @@ -11605,7 +12083,7 @@ static void decode_opc (CPUState *env,
> DisasContext
> > *ctx, int *is_branch)
> >      int32_t offset;
> >      int rs, rt, rd, sa;
> >      uint32_t op, op1, op2;
> > -    int16_t imm;
> > +    int16_t imm, imm10;
> >
> >      /* make sure instructions are on a word boundary */
> >      if (ctx->pc & 0x3) {
> > @@ -11634,6 +12112,9 @@ static void decode_opc (CPUState *env,
> DisasContext
> > *ctx, int *is_branch)
> >      rd = (ctx->opcode >> 11) & 0x1f;
> >      sa = (ctx->opcode >> 6) & 0x1f;
> >      imm = (int16_t)ctx->opcode;
> > +    /* 10 bit Immediate value For SEQI,SNEI */
> > +    imm10 = (ctx->opcode >> 6) & 0x3ff;
> > +
> >      switch (op) {
> >      case OPC_SPECIAL:
> >          op1 = MASK_SPECIAL(ctx->opcode);
> > @@ -11859,6 +12340,71 @@ 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_insn(env, ctx, ISA_MIPS3);
> > +            check_mips_64(ctx);
> > +            gen_muldiv(ctx, op1, rs, rt);
> > +            tcg_gen_mov_tl(cpu_gpr[rd], cpu_LO[0]);
> > +            break;
> > +        case OPC_CINS:
> > +            check_insn(env, ctx, ISA_MIPS64R2);
> > +            check_mips_64(ctx);
> > +            gen_bitops(ctx, op1, rt, rs, sa, rd);
> > +            break;
> > +        case OPC_CINS32:
> > +            check_mips_64(ctx);
> > +            gen_bitops(ctx, op1, rt, rs, sa, rd);
> > +            break;
> > +        case OPC_MTM0:
> > +            check_mips_64(ctx);
> > +            gen_LMI(env, ctx, op1, rs, rt, rd);
> > +            break;
> > +        case OPC_MTM1:
> > +            check_mips_64(ctx);
> > +            gen_LMI(env, ctx, op1, rs, rt, rd);
> > +            break;
> > +        case OPC_MTM2:
> > +            check_mips_64(ctx);
> > +            gen_LMI(env, ctx, op1, rs, rt, rd);
> > +            break;
> > +        case OPC_MTP0:
> > +            check_mips_64(ctx);
> > +            gen_LMI(env, ctx, op1, rs, rt, rd);
> > +            break;
> > +        case OPC_MTP1:
> > +            check_mips_64(ctx);
> > +            gen_LMI(env, ctx, op1, rs, rt, rd);
> > +            break;
> > +        case OPC_MTP2:
> > +            check_mips_64(ctx);
> > +            gen_LMI(env, ctx, op1, rs, rt, rd);
> > +            break;
> > +        case OPC_VMULU:
> > +            check_mips_64(ctx);
> > +            gen_LMI(env, ctx, op1, rs, rt, rd);
> > +            break;
> > +        case OPC_BADDU:
> > +            gen_arith(env, ctx, op1, rd, rs, rt);
> > +            break;
> > +        case OPC_EXTS:
> > +            check_mips_64(ctx);
> > +            gen_exts(env, ctx, op1, rt, rs, sa, rd);
> > +            break;
> > +        case OPC_EXTS32:
> > +            check_mips_64(ctx);
> > +            gen_exts(env, ctx, op1, rt, rs, sa, rd);
> > +            break;
> > +        case OPC_SAA:
> > +            gen_saa(env, ctx, op1, rt, rs);
> > +            break;
> > +        case OPC_SAAD:
> > +            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);
> > @@ -11878,13 +12424,24 @@ static void decode_opc (CPUState *env,
> > DisasContext *ctx, int *is_branch)
> >              break;
> >          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:
> >              check_insn(env, ctx, INSN_LOONGSON2F);
> >              gen_loongson_integer(ctx, op1, rd, rs, rt);
> >              break;
> > +        case OPC_MULT_G_2F:
> > +            if (!TARGET_OCTEON) {
> > +                check_insn(env, ctx, INSN_LOONGSON2F);
> > +                gen_loongson_integer(ctx, op1, rd, rs, rt);
> > +            } else {
> > +#if defined(TARGET_MIPS64)
> > +                /* Cavium Specific vmm0 */
> > +                check_mips_64(ctx);
> > +                gen_LMI(env, ctx, op1, rs, rt, rd);
> > +#endif
> > +            }
> > +            break;
> >  #if defined(TARGET_MIPS64)
> >          case OPC_DCLO:
> >          case OPC_DCLZ:
> > @@ -11892,7 +12449,6 @@ static void decode_opc (CPUState *env,
> DisasContext
> > *ctx, int *is_branch)
> >              check_mips_64(ctx);
> >              gen_cl(ctx, op1, rd, rs);
> >              break;
> > -        case OPC_DMULT_G_2F:
> >          case OPC_DMULTU_G_2F:
> >          case OPC_DDIV_G_2F:
> >          case OPC_DDIVU_G_2F:
> > @@ -11901,6 +12457,39 @@ 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_DMULT_G_2F:
> > +            if (!TARGET_OCTEON) {
> > +                check_insn(env, ctx, INSN_LOONGSON2F);
> > +                gen_loongson_integer(ctx, op1, rd, rs, rt);
> > +            } else {
> > +                /* Cavium Specific instruction v3mulu */
> > +                check_mips_64(ctx);
> > +                gen_LMI(env, ctx, op1, rs, rt, rd);
> > +            }
> > +            break;
> > +        case OPC_SEQ:
> > +            check_mips_64(ctx);
> > +            gen_seqsne(ctx, op1, rd, rs, rt);
> > +            break;
> > +        case OPC_SNE:
> > +            check_mips_64(ctx);
> > +            gen_seqsne(ctx, op1, rd, rs, rt);
> > +            break;
> > +        case OPC_SEQI:
> > +            check_mips_64(ctx);
> > +            gen_set_imm(env, op1, rt, rs, imm10);
> > +            break;
> > +        case OPC_SNEI:
> > +            check_mips_64(ctx);
> > +            gen_set_imm(env, op1, rt, rs, imm10);
> > +            break;
> > +        case OPC_POP:
> > +            insn_opc_pop(ctx, env, op1, rd, rs, rt);
> > +            break;
> > +        case OPC_DPOP:
> > +            check_mips_64(ctx);
> > +            insn_opc_dpop(ctx, env, op1, rd, rs, rt);
> > +            break;
> >  #endif
> >          default:            /* Invalid */
> >              MIPS_INVAL("special2");
> > @@ -12192,10 +12781,32 @@ 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 TARGET_OCTEON is set these opcodes will belong to Cavium */
> > +    case OPC_LWC2: /*BBIT0*/
> > +        if(TARGET_OCTEON) {
> > +            gen_compute_branch(ctx, op, 4, rs, rt, imm << 2);
> > +            *is_branch = 1;
> > +            break;
> > +        }
> > +    case OPC_LDC2: /*BBIT032*/
> > +        if(TARGET_OCTEON) {
> > +            gen_compute_branch(ctx, op, 4, rs, rt, imm << 2);
> > +            *is_branch = 1;
> > +            break;
> > +        }
> > +    case OPC_SWC2: /*BBIT1*/
> > +        if(TARGET_OCTEON) {
> > +            gen_compute_branch(ctx, op, 4, rs, rt, imm << 2);
> > +            *is_branch = 1;
> > +            break;
> > +        }
> > +    case OPC_SDC2: /*BBIT132*/
> > +        if(TARGET_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);
> > @@ -12584,6 +13195,18 @@ static void mips_tcg_init(void)
> >      cpu_dspctrl = tcg_global_mem_new(TCG_AREG0,
> >                                       offsetof(CPUState,
> > active_tc.DSPControl),
> >                                       "DSPControl");
> > +    mpl0 = tcg_global_mem_new(TCG_AREG0,
> > +                              offsetof(CPUState, Reg.MPL0), "MPL0");
> > +    mpl1 = tcg_global_mem_new(TCG_AREG0,
> > +                              offsetof(CPUState, Reg.MPL1), "MPL1");
> > +    mpl2 = tcg_global_mem_new(TCG_AREG0,
> > +                              offsetof(CPUState, Reg.MPL2), "MPL2");
> > +    p0 = tcg_global_mem_new(TCG_AREG0,
> > +                            offsetof(CPUState, Reg.P0), "P0");
> > +    p1 = tcg_global_mem_new(TCG_AREG0,
> > +                            offsetof(CPUState, Reg.P1), "P1");
> > +    p2 = tcg_global_mem_new(TCG_AREG0,
> > +                            offsetof(CPUState, Reg.P2), "P2");
> >      bcond = tcg_global_mem_new(TCG_AREG0,
> >                                 offsetof(CPUState, bcond), "bcond");
> >      btarget = tcg_global_mem_new(TCG_AREG0,
> > @@ -12607,6 +13230,18 @@ static void mips_tcg_init(void)
> >
> >  #include "translate_init.c"
> >
> > +#if defined(TARGET_MIPS64)
> > +
> > +static void set_cvmctl_register(CPUMIPSState *env)
> > +{
> > +    env->CvmCtlRegister.cvmctl = env->CvmCtlRegister.cvmctl
> > +                                 ^ env->CvmCtlRegister.cvmctl;
> > +    env->CvmCtlRegister.cvmctl =
> > FUSE_START_BIT(env->CvmCtlRegister.cvmctl);
> > +    env->CvmCtlRegister.cvmctl = KASUMI(env->CvmCtlRegister.cvmctl);
> > +    env->CvmCtlRegister.cvmctl = IPPCI(env->CvmCtlRegister.cvmctl);
> > +    env->CvmCtlRegister.cvmctl = IPTI(env->CvmCtlRegister.cvmctl);
> > +}
> > +#endif
> >  CPUMIPSState *cpu_mips_init (const char *cpu_model)
> >  {
> >      CPUMIPSState *env;
> > @@ -12619,6 +13254,10 @@ CPUMIPSState *cpu_mips_init (const char
> *cpu_model)
> >      env->cpu_model = def;
> >      env->cpu_model_str = cpu_model;
> >
> > +#if defined(TARGET_MIPS64)
> > +    /*Function for setting cvmctl register*/
> > +    set_cvmctl_register(env);
> > +#endif
> >      cpu_exec_init(env);
> >  #ifndef CONFIG_USER_ONLY
> >      mmu_init(env, def);
> > --
> > 1.7.3.4
>
Khansa Butt April 9, 2011, 9:57 a.m. UTC | #6
Please see the online comments highlighted in red.
I'll be sending corrected Patches to the mailing list.

On Wed, Mar 30, 2011 at 9:38 PM, Nathan Froyd <froydnj@codesourcery.com>wrote:

> On Sat, Mar 26, 2011 at 11:58:37AM +0500, Khansa Butt wrote:
> > Subject: [PATCH] MIPS64 user mode emulation in QEMU
> >  This patch adds support for Cavium Network's
> >  Octeon 57XX user mode instructions.  Octeon
> >  57xx is based on MIPS64.  So this patch is
> >  the first MIPS64 User Mode Emulation in QEMU
> >  This is the team(Khansa Butt, Ehsan-ul-Haq, Abdul Qadeer, Abdul Waheed)
> >  work of HPCNL Lab at KICS-UET Lahore.
>
> Thanks for doing this.  As already noted, this patch should be split
> into at least two patches: one to add Octeon-specific instructions in
> target-mips/ and one adding the necessary linux-user bits.
>
> > +extern int TARGET_OCTEON;
>
> I don't think a global like this is the right way to go.  Perhaps the
> elfload.c code should set a flag in image_info , which can then be used
> to set a flag in CPUMIPSState later on.
>


A variable is declared in image_info to set a flag in CPUMIPSState and
discarded a global variable
@@ -51,6 +51,7 @@ struct image_info {
         abi_ulong       arg_start;
         abi_ulong       arg_end;
  int personality;
+ int elf_arch;


>
> If we must use a global variable, it should be declared in
> target-mips/cpu.h.
>
> > @@ -2013,7 +2024,8 @@ void cpu_loop(CPUMIPSState *env)
> >                                   env->active_tc.gpr[5],
> >                                   env->active_tc.gpr[6],
> >                                   env->active_tc.gpr[7],
> > -                                 arg5, arg6/*, arg7, arg8*/);
> > +                                 env->active_tc.gpr[8],
> > +                                 env->active_tc.gpr[9]/*, arg7, arg8*/);
> >              }
> >              if (ret == -TARGET_QEMU_ESIGRETURN) {
> >                  /* Returning from a successful sigreturn syscall.
>
> This change breaks O32 binaries; it needs to be done in a different way.
>


The above line has been changed with following code snippet
+#if defined(TARGET_MIPS64)
+                ret = do_syscall(env, env->active_tc.gpr[2],
+                                 env->active_tc.gpr[4],
+                                 env->active_tc.gpr[5],
+                                 env->active_tc.gpr[6],
+                                 env->active_tc.gpr[7],
+                                 env->active_tc.gpr[8],
+                                 env->active_tc.gpr[9]);
+#else
                 ret = do_syscall(env, env->active_tc.gpr[2],
                                  env->active_tc.gpr[4],
                                  env->active_tc.gpr[5],
                                  env->active_tc.gpr[6],
                                  env->active_tc.gpr[7],
                                  arg5, arg6/*, arg7, arg8*/);
+#endif



> > diff --git a/linux-user/syscall.c b/linux-user/syscall.c
> > index 499c4d7..47fef05 100644
> > --- a/linux-user/syscall.c
> > +++ b/linux-user/syscall.c
> > @@ -7195,6 +7195,8 @@ abi_long do_syscall(void *cpu_env, int num,
> abi_long
> > arg1,
> >      case TARGET_NR_set_thread_area:
> >  #if defined(TARGET_MIPS)
> >        ((CPUMIPSState *) cpu_env)->tls_value = arg1;
> > +       /*tls entry is moved to k0 so that this can be used later*/
> > +      ((CPUMIPSState *) cpu_env)->active_tc.gpr[26] = arg1;
> >        ret = 0;
> >        break;
> >  #elif defined(TARGET_CRIS)
>
> I believe this is only correct for Octeon binaries; it's not how the
> rest of the MIPS world works.  It therefore needs to be conditional on
> Octeon-ness.
>
> The above thing has been made octeon specific


> > --- a/target-mips/cpu.h
> > +++ b/target-mips/cpu.h
> > @@ -140,6 +140,20 @@ typedef struct mips_def_t mips_def_t;
> >  #define MIPS_FPU_MAX 1
> >  #define MIPS_DSP_ACC 4
> >
> > +typedef struct cavium_mul cavium_mul;
> > +struct cavium_mul {
> > + target_ulong MPL0;
> > + target_ulong MPL1;
> > + target_ulong MPL2;
> > + target_ulong P0;
> > + target_ulong P1;
> > + target_ulong P2;
> > +};
> > +typedef struct cvmctl_register cvmctl_register;
> > +struct cvmctl_register {
> > + target_ulong cvmctl;
> > +};
>
> The indentation here needs to be fixed.  I don't think there's any
> reason why these need to be defined outside TCState, either.
>

Octeon register in TCState as follows
@@ -171,6 +176,15 @@ 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;
+    /* Octeon specific Coprocessor 0 register */
+    target_ulong cvmctl;
 };




> > diff --git a/target-mips/translate.c b/target-mips/translate.c
> > index cce77be..9c3d772 100644
> > --- a/target-mips/translate.c
> > +++ b/target-mips/translate.c
> > @@ -36,6 +36,15 @@
> >  #define GEN_HELPER 1
> >  #include "helper.h"
> >
> > +int TARGET_OCTEON;
> > +#if defined(TARGET_MIPS64)
> > +/*Macros for setting values of cvmctl registers*/
> > +#define FUSE_START_BIT(cvmctl)(cvmctl | 0x80000000)
> > +#define KASUMI(cvmctl)(cvmctl | 0x20000000)
> > +#define IPPCI(cvmctl)(cvmctl | 0x380)
> > +#define IPTI(cvmctl)(cvmctl | 0x70)
> > +#endif
>
> Please follow existing style; spaces between the comment and comment
> markers (many examples in translate.c, not just here) and spaces between
> the macro argument list and definition.
>
> > @@ -779,7 +818,9 @@ static inline void gen_op_addr_add (DisasContext
> *ctx,
> > TCGv ret, TCGv arg0, TCGv
> >         See the MIPS64 PRA manual, section 4.10. */
> >      if (((ctx->hflags & MIPS_HFLAG_KSU) == MIPS_HFLAG_UM) &&
> >          !(ctx->hflags & MIPS_HFLAG_UX)) {
> > -        tcg_gen_ext32s_i64(ret, ret);
> > +        /*This function sign extend 32 bit value to 64 bit, was causing
> > error
> > +          when ld instruction came.Thats why it is commmented out*/
> > +       /* tcg_gen_ext32s_i64(ret, ret);*/
> >      }
> >  #endif
> >  }
>
> Um, no.  If you needed to comment this out, you have a bug someplace
> else.  Don't paper over the bug here.
>


The above behavior when  ld instruction came was due to env->hflags had
 not been 'or' ed with mips64 user mode flag(MIPS_HFLAG_UX) so now following
line is added in translate.c: cpu_rest()
#ifdef TARGET_MIPS64
+    env->hflags |=  MIPS_HFLAG_UX;
     if (env->active_fpu.fcr0 & (1 << FCR0_F64)) {
         env->hflags |= MIPS_HFLAG_F64;
     }



> > +        case OPC_VMULU:
> > +        case OPC_V3MULU:
>
> These two are large enough that they should be done as out-of-line
> helpers.
>

Out-of-line helper function has been implemented


>
> Also, since all these new instructions are Octeon-specific, there should
> be checks emitted to ensure that they produce appropriate errors when
> non-Octeon hardware is being simulated, similar in style to
> check_mips_64.
>

check for octeon specific instructions
static inline void check_octeon(DisasContext *ctx, CPUState *env)
+{
+    if (!env->TARGET_OCTEON)
+        generate_exception(ctx, EXCP_RI);
+}




>
> >  /* Arithmetic */
> >  static void gen_arith (CPUState *env, DisasContext *ctx, uint32_t opc,
> >                         int rd, int rs, int rt)
> >  {
> >      const char *opn = "arith";
> >
> > +    target_ulong mask = 0xFF;
>
> I don't think it's really necessary to have this, but if you feel it's
> necessary, please move the declaration closer to the point of use.
>
> > +#if defined(TARGET_MIPS64)
> > +static void gen_seqsne (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();
> > +    switch (opc) {
> > +    case OPC_SEQ:
> > +        {
> > +            tcg_gen_xor_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]);
> > +            gen_load_gpr(t0, rd);
> > +            tcg_gen_setcondi_tl(TCG_COND_LTU, cpu_gpr[rd], t0, 1);
> > +        }
> > +        opn = "seq";
> > +        break;
>
> This looks like you are comparing rd with itself?
>


t0 is actually compared with 1. if t0 <1 then rd =1
for reference check slti instruction of mips64r2
switch (opc) {
    case OPC_SLTI:
        tcg_gen_setcondi_tl(TCG_COND_LT, cpu_gpr[rt], t0, uimm);
        opn = "slti";



> > +    case OPC_SNE:
> > +        {
> > +            tcg_gen_xor_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]);
> > +            gen_load_gpr(t0, rd);
> > +            gen_load_gpr(t1, 0);
> > +            tcg_gen_setcond_tl(TCG_COND_LTU, cpu_gpr[rd], t1, t0);
>
> You could use setcondi here by reversing the condition.
>


This is set if not equal instruction. if rs != rt, rd has some value greater
than 1 (because of
tcg_gen_xor_tl) so if t1 < t0(in  tcg_gen_setcond_tl) rd will be 1. that's
wat we needed "set if not
equal"



> > +#if defined(TARGET_MIPS64)
> > +static void insn_opc_pop (DisasContext *ctx, CPUState *env, uint32_t
> opc,
> > +                          int rd, int rs, int rt)
> > +static void insn_opc_dpop (DisasContext *ctx, CPUState *env, uint32_t
> opc,
> > +                           int rd, int rs, int rt)
>
> These should also be done as out-of-line helpers.
>
> > @@ -2983,7 +3408,44 @@ static void gen_compute_branch (DisasContext *ctx,
> > uint32_t opc,
> >      tcg_temp_free(t0);
> >      tcg_temp_free(t1);
> >  }
> > +/*For cavium specific extract instructions*/
> > +#if defined(TARGET_MIPS64)
> > +static void gen_exts (CPUState *env,DisasContext *ctx, uint32_t opc, int
> > rt,
> > +                      int rs, int lsb, int msb)
> > +{
> > +    TCGv t0 = tcg_temp_new();
> > +    TCGv t1 = tcg_temp_new();
> > +    target_ulong mask;
> > +    gen_load_gpr(t1, rs);
> > +    switch (opc) {
> > +    case OPC_EXTS:
> > +        tcg_gen_shri_tl(t0, t1, lsb);
> > +        tcg_gen_andi_tl(t0, t0, (1ULL << (msb + 1)) - 1);
> > +        /* To sign extened the remaining bits according to
> > +           the msb of the bit field */
> > +        mask = 1ULL << msb;
> > +        tcg_gen_andi_tl(t1, t0, mask);
> > +        tcg_gen_addi_tl(t1, t1, -1);
> > +        tcg_gen_not_i64(t1, t1);
> > +        tcg_gen_or_tl(t0, t0, t1);
>
> You can use tcg_gen_orc_tl here and elsewhere.
>
> -Nathan
>
diff mbox

Patch

diff --git a/configure b/configure
index 438219b..045a4ef 100755
--- a/configure
+++ b/configure
@@ -1011,6 +1011,7 @@  cris-linux-user \
 m68k-linux-user \
 microblaze-linux-user \
 mips-linux-user \
+mips64-linux-user \
 mipsel-linux-user \
 ppc-linux-user \
 ppc64-linux-user \
diff --git a/default-configs/mips64-linux-user.mak
b/default-configs/mips64-linux-user.mak
new file mode 100644
index 0000000..1598bfc
--- /dev/null
+++ b/default-configs/mips64-linux-user.mak
@@ -0,0 +1 @@ 
+# Default configuration for mips64-linux-user
diff --git a/exec.c b/exec.c
index 49c28b1..ee3f78e 100644
--- a/exec.c
+++ b/exec.c
@@ -2441,6 +2441,7 @@  int page_check_range(target_ulong start, target_ulong
len, int flags)
     for (addr = start, len = end - start;
          len != 0;
          len -= TARGET_PAGE_SIZE, addr += TARGET_PAGE_SIZE) {
+        addr  &= qemu_host_page_mask;
         p = page_find(addr >> TARGET_PAGE_BITS);
         if( !p )
             return -1;
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 33d776d..60fe85e 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -16,6 +16,8 @@ 
 #include "qemu.h"
 #include "disas.h"

+extern int TARGET_OCTEON;
+
 #ifdef _ARCH_PPC64
 #undef ARCH_DLINFO
 #undef ELF_PLATFORM
@@ -25,6 +27,9 @@ 
 #undef ELF_ARCH
 #endif

+#define EF_MIPS_MARCH 16711680
+#define E_MIPS_MACH_OCTEON 9109504
+
 #define ELF_OSABI   ELFOSABI_SYSV

 /* from personality.h */
@@ -1313,7 +1318,7 @@  static void load_elf_image(const char *image_name, int
image_fd,
             vaddr_po = TARGET_ELF_PAGEOFFSET(vaddr);
             vaddr_ps = TARGET_ELF_PAGESTART(vaddr);

-            error = target_mmap(vaddr_ps, eppnt->p_filesz + vaddr_po,
+            error = target_mmap(vaddr_ps, eppnt->p_memsz + vaddr_po,
                                 elf_prot, MAP_PRIVATE | MAP_FIXED,
                                 image_fd, eppnt->p_offset - vaddr_po);
             if (error == -1) {
@@ -1588,7 +1593,13 @@  int load_elf_binary(struct linux_binprm * bprm,
struct target_pt_regs * regs,
        If we do nothing, we'll have overwritten this when we re-use
bprm->buf
        when we load the interpreter.  */
     elf_ex = *(struct elfhdr *)bprm->buf;
-
+#if defined(TARGET_MIPS64)
+    if ((elf_ex.e_flags & EF_MIPS_MARCH) == E_MIPS_MACH_OCTEON) {
+        TARGET_OCTEON = 1;
+    } else {
+        TARGET_OCTEON = 0;
+    }
+#endif
     bprm->p = copy_elf_strings(1, &bprm->filename, bprm->page, bprm->p);
     bprm->p = copy_elf_strings(bprm->envc,bprm->envp,bprm->page,bprm->p);
     bprm->p = copy_elf_strings(bprm->argc,bprm->argv,bprm->page,bprm->p);
diff --git a/linux-user/main.c b/linux-user/main.c
index 0d627d6..8b4b90b 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -1937,10 +1937,16 @@  static int do_store_exclusive(CPUMIPSState *env)
     int d;

     addr = env->lladdr;
+    /* 64 bit address is converted to 32 bit value so that a valid
+    * l1_map value can be accessed. This thing is needed for target
+    * mips64 and host 32 bit x86
+    */
+    addr &= qemu_host_page_mask;
     page_addr = addr & TARGET_PAGE_MASK;
     start_exclusive();
     mmap_lock();
     flags = page_get_flags(page_addr);
+    addr = env->lladdr;
     if ((flags & PAGE_READ) == 0) {
         segv = 1;
     } else {
@@ -1978,7 +1984,8 @@  static int do_store_exclusive(CPUMIPSState *env)
 void cpu_loop(CPUMIPSState *env)
 {
     target_siginfo_t info;
-    int trapnr, ret;
+    int trapnr;
+    abi_long ret;
     unsigned int syscall_num;

     for(;;) {
@@ -1987,7 +1994,11 @@  void cpu_loop(CPUMIPSState *env)
         cpu_exec_end(env);
         switch(trapnr) {
         case EXCP_SYSCALL:
+#if defined(TARGET_MIPS64)
+            syscall_num = env->active_tc.gpr[2] - 5000;
+#else
             syscall_num = env->active_tc.gpr[2] - 4000;
+#endif
             env->active_tc.PC += 4;
             if (syscall_num >= sizeof(mips_syscall_args)) {
                 ret = -ENOSYS;
@@ -2013,7 +2024,8 @@  void cpu_loop(CPUMIPSState *env)
                                  env->active_tc.gpr[5],
                                  env->active_tc.gpr[6],
                                  env->active_tc.gpr[7],
-                                 arg5, arg6/*, arg7, arg8*/);
+                                 env->active_tc.gpr[8],
+                                 env->active_tc.gpr[9]/*, arg7, arg8*/);
             }
             if (ret == -TARGET_QEMU_ESIGRETURN) {
                 /* Returning from a successful sigreturn syscall.
@@ -2926,7 +2938,9 @@  int main(int argc, char **argv, char **envp)
 #endif
 #elif defined(TARGET_MIPS)
 #if defined(TARGET_ABI_MIPSN32) || defined(TARGET_ABI_MIPSN64)
-        cpu_model = "20Kc";
+        /* we use this model so that we can decode MIPS64r2
+           reserved instruction */
+        cpu_model = "MIPS64R2-generic";
 #else
         cpu_model = "24Kf";
 #endif
diff --git a/linux-user/mips64/syscall.h b/linux-user/mips64/syscall.h
index 668a2b9..1395e61 100644
--- a/linux-user/mips64/syscall.h
+++ b/linux-user/mips64/syscall.h
@@ -217,5 +217,7 @@  struct target_pt_regs {
 #define TARGET_ENOTRECOVERABLE 166     /* State not recoverable */


+/* Nasty hack: define a fake errno value for use by sigreturn.  */
+#define TARGET_QEMU_ESIGRETURN 255

 #define UNAME_MACHINE "mips64"
diff --git a/linux-user/signal.c b/linux-user/signal.c
index c846b8c..114116c 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -2410,7 +2410,8 @@  void sparc64_get_context(CPUSPARCState *env)
 #endif
 #elif defined(TARGET_ABI_MIPSN64)

-# warning signal handling not implemented
+/*this line is commented out to avoid compile time error*/
+/*# warning signal handling not implemented*/

 static void setup_frame(int sig, struct target_sigaction *ka,
  target_sigset_t *set, CPUState *env)
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 499c4d7..47fef05 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -7195,6 +7195,8 @@  abi_long do_syscall(void *cpu_env, int num, abi_long
arg1,
     case TARGET_NR_set_thread_area:
 #if defined(TARGET_MIPS)
       ((CPUMIPSState *) cpu_env)->tls_value = arg1;
+       /*tls entry is moved to k0 so that this can be used later*/
+      ((CPUMIPSState *) cpu_env)->active_tc.gpr[26] = arg1;
       ret = 0;
       break;
 #elif defined(TARGET_CRIS)
diff --git a/target-mips/cpu.h b/target-mips/cpu.h
index 2419aa9..59bcc0f 100644
--- a/target-mips/cpu.h
+++ b/target-mips/cpu.h
@@ -140,6 +140,20 @@  typedef struct mips_def_t mips_def_t;
 #define MIPS_FPU_MAX 1
 #define MIPS_DSP_ACC 4

+typedef struct cavium_mul cavium_mul;
+struct cavium_mul {
+ target_ulong MPL0;
+ target_ulong MPL1;
+ target_ulong MPL2;
+ target_ulong P0;
+ target_ulong P1;
+ target_ulong P2;
+};
+typedef struct cvmctl_register cvmctl_register;
+struct cvmctl_register {
+ target_ulong cvmctl;
+};
+
 typedef struct TCState TCState;
 struct TCState {
     target_ulong gpr[32];
@@ -178,6 +192,8 @@  struct CPUMIPSState {
     TCState active_tc;
     CPUMIPSFPUContext active_fpu;

+    cavium_mul Reg;
+    cvmctl_register CvmCtlRegister;
     uint32_t current_tc;
     uint32_t current_fpu;

diff --git a/target-mips/translate.c b/target-mips/translate.c
index cce77be..9c3d772 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -36,6 +36,15 @@ 
 #define GEN_HELPER 1
 #include "helper.h"

+int TARGET_OCTEON;
+#if defined(TARGET_MIPS64)
+/*Macros for setting values of cvmctl registers*/
+#define FUSE_START_BIT(cvmctl)(cvmctl | 0x80000000)
+#define KASUMI(cvmctl)(cvmctl | 0x20000000)
+#define IPPCI(cvmctl)(cvmctl | 0x380)
+#define IPTI(cvmctl)(cvmctl | 0x70)
+#endif
+
 //#define MIPS_DEBUG_DISAS
 //#define MIPS_DEBUG_SIGN_EXTENSIONS

@@ -70,6 +79,11 @@  enum {
     OPC_JAL      = (0x03 << 26),
     OPC_JALS     = OPC_JAL | 0x5,
     OPC_BEQ      = (0x04 << 26),  /* Unconditional if rs = rt = 0 (B) */
+    /* Cavium Specific */
+    OPC_BBIT1    = (0x3a << 26),  /*jump on bit set, cavium specific*/
+    OPC_BBIT132  = (0x3e << 26),  /*jump on bit set(one of the upper 32
bits)*/
+    OPC_BBIT0    = (0x32 << 26),  /*jump on bit clear, cavium specific*/
+    OPC_BBIT032  = (0x36 << 26),  /*jump on bit set(one of the upper 32
bits)*/
     OPC_BEQL     = (0x14 << 26),