From patchwork Fri Apr 29 06:19:31 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Khansa Butt X-Patchwork-Id: 93388 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [140.186.70.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id BAB13B6FD1 for ; Fri, 29 Apr 2011 16:20:01 +1000 (EST) Received: from localhost ([::1]:43626 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QFh3W-0007Qu-I2 for incoming@patchwork.ozlabs.org; Fri, 29 Apr 2011 02:19:58 -0400 Received: from eggs.gnu.org ([140.186.70.92]:42230) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QFh3B-0007Gb-8v for qemu-devel@nongnu.org; Fri, 29 Apr 2011 02:19:40 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1QFh37-0002YK-D1 for qemu-devel@nongnu.org; Fri, 29 Apr 2011 02:19:37 -0400 Received: from mail-qw0-f45.google.com ([209.85.216.45]:58526) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QFh37-0002YG-3M for qemu-devel@nongnu.org; Fri, 29 Apr 2011 02:19:33 -0400 Received: by qwj8 with SMTP id 8so1897875qwj.4 for ; Thu, 28 Apr 2011 23:19:32 -0700 (PDT) MIME-Version: 1.0 Received: by 10.229.63.143 with SMTP id b15mr3615779qci.136.1304057971559; Thu, 28 Apr 2011 23:19:31 -0700 (PDT) Received: by 10.229.211.73 with HTTP; Thu, 28 Apr 2011 23:19:31 -0700 (PDT) Date: Fri, 29 Apr 2011 11:19:31 +0500 Message-ID: From: Khansa Butt To: Aurelien Jarno , qemu-devel@nongnu.org X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6 (newer, 2) X-Received-From: 209.85.216.45 Subject: [Qemu-devel] [PATCH 2/3] target-mips:Support for Cavium-Octeon specific instructions X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org From f699dbfdca62c5af92d764673b2300131d26263e Mon Sep 17 00:00:00 2001 From: Ehsan-ul-Haq, Abdul Qadeer, Abdul Waheed, Khansa Butt < khansa@kics.edu.pk> Date: Wed, 27 Apr 2011 16:08:16 +0500 Subject: [PATCH 2/3] target-mips:Support for Cavium-Octeon specific instructions Signed-off-by: Khansa Butt --- host-utils.c | 1 + target-mips/cpu.h | 7 + target-mips/helper.h | 5 + target-mips/op_helper.c | 62 +++++++ target-mips/translate.c | 445 +++++++++++++++++++++++++++++++++++++++++++++-- 5 files changed, 509 insertions(+), 11 deletions(-) OPC_BNEL = (0x15 << 26), @@ -265,6 +270,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 +513,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; @@ -1419,7 +1449,30 @@ 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/set if not equal immidiate */ +static void gen_set_imm(CPUState *env, uint32_t opc, + int rt, int rs, int16_t imm) +{ + TCGv t0; + const char *opn = "imm set"; + t0 = tcg_temp_new(); + gen_load_gpr(t0, rs); + switch (opc) { + case OPC_SEQI: + tcg_gen_xori_tl(t0, t0, imm); + tcg_gen_setcondi_tl(TCG_COND_LT, cpu_gpr[rt], t0, 1); + opn = "seqi"; + break; + case OPC_SNEI: + tcg_gen_xori_tl(t0, t0, imm); + tcg_gen_setcondi_tl(TCG_COND_GT, cpu_gpr[rt], t0, 0); + opn = "snei"; + break; + } + tcg_temp_free(t0); +} +#endif /* Logic with immediate operand */ static void gen_logic_imm (CPUState *env, uint32_t opc, int rt, int rs, int16_t imm) { @@ -1583,6 +1636,78 @@ 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) +static void gen_LMI (CPUMIPSState *env, DisasContext *ctx, uint32_t opc, + int rs, int rt, int rd) +{ + const char *opn = "LMI"; + TCGv t0, t1; + t0 = tcg_temp_new(); + t1 = tcg_temp_new(); + gen_load_gpr(t0, rs); + gen_load_gpr(t1, rt); + switch (opc) { + case OPC_MTM0: + tcg_gen_mov_tl(mpl0, t0); + 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, t0); + 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, t0); + 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, t0); + opn = "mtp0"; + break; + case OPC_MTP1: + tcg_gen_mov_tl(p1, t0); + opn = "mtp1"; + break; + case OPC_MTP2: + tcg_gen_mov_tl(p2, t0); + opn = "mtp2"; + break; + case OPC_VMM0: + tcg_gen_mul_i64(t0, t0, mpl0); + tcg_gen_add_tl(t1, t1, t0); + tcg_gen_add_tl(t1, t1, p0); + gen_store_gpr(t1, rd); + tcg_gen_mov_tl(mpl0, t1); + tcg_gen_movi_tl(p0, 0); + tcg_gen_movi_tl(p1, 0); + tcg_gen_movi_tl(p2, 0); + opn = "vmm0"; + break; + case OPC_VMULU: + gen_helper_vmulu(t0, t0, t1); + gen_store_gpr(t0, rd); + opn = "vmulu"; + break; + case OPC_V3MULU: + gen_load_gpr(t0, rs); + gen_load_gpr(t1, rt); + gen_helper_v3mulu(t0, t0, t1); + gen_store_gpr(t0, rd); + opn = "v3mulu"; + break; + } + tcg_temp_free(t0); + tcg_temp_free(t1); +} +#endif /* Arithmetic */ static void gen_arith (CPUState *env, DisasContext *ctx, uint32_t opc, @@ -1637,6 +1762,30 @@ static void gen_arith (CPUState *env, DisasContext *ctx, uint32_t opc, } opn = "addu"; break; + case OPC_BADDU: + { + TCGv t0 = tcg_temp_new(); + TCGv t1 = tcg_temp_new(); + gen_load_gpr(t0, rs); + gen_load_gpr(t1, rt); + tcg_gen_add_tl(t0, t1, t0); + tcg_gen_ext8u_tl(t0, t0); + gen_store_gpr(t0, rd); + tcg_temp_free(t0); + tcg_temp_free(t1); + } + opn = "baddu"; + break; + case OPC_DMUL: + { + TCGv t0 = tcg_temp_new(); + TCGv t1 = tcg_temp_new(); + gen_load_gpr(t0, rs); + gen_load_gpr(t1, rt); + tcg_gen_mul_i64(cpu_gpr[rd], t0, t1); + } + opn = "dmul"; + break; case OPC_SUB: { TCGv t0 = tcg_temp_local_new(); @@ -2013,7 +2162,69 @@ 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(); + gen_load_gpr(t0, rs); + gen_load_gpr(t1, rt); + switch (opc) { + case OPC_SEQ: + tcg_gen_xor_tl(t0, t0, t1); + tcg_gen_setcondi_tl(TCG_COND_LTU, cpu_gpr[rd], t0, 1); + opn = "seq"; + break; + case OPC_SNE: + tcg_gen_xor_tl(t0, t0, t1); + tcg_gen_setcondi_tl(TCG_COND_GTU, cpu_gpr[rd], t0, 0); + opn = "sne"; + break; + default: + MIPS_INVAL(opn); + generate_exception(ctx, EXCP_RI); + goto out; + } +out: + tcg_temp_free(t0); + tcg_temp_free(t1); + +} +/* FIXME: something else should be done for emulating SMP system. */ +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) { @@ -2368,7 +2579,28 @@ 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 gen_pop_count (DisasContext *ctx, uint32_t opc, int rd, int rs) +{ + const char *opn = "pop"; + TCGv t0; + t0 = tcg_temp_new(); + gen_load_gpr(t0, rs); + switch (opc) { + case OPC_DPOP: + gen_helper_dpop(t0, t0); + gen_store_gpr(t0, rd); + opn = "dpop"; + break; + case OPC_POP: + gen_helper_pop(t0, t0); + gen_store_gpr(t0, rd); + opn = "pop"; + break; + } + tcg_temp_free(t0); +} +#endif /* Godson integer instructions */ static void gen_loongson_integer (DisasContext *ctx, uint32_t opc, int rd, int rs, int rt) @@ -2705,6 +2937,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 +2963,22 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc, } btgt = ctx->pc + insn_bytes + offset; break; + case OPC_BBIT0: + case OPC_BBIT1: + gen_load_gpr(t0, rs); + maskb = 1ULL << rt; + tcg_gen_andi_tl(t0, t0, maskb); + bcond_compute = 1; + btgt = ctx->pc + insn_bytes + offset; + break; + case OPC_BBIT032: + case OPC_BBIT132: + gen_load_gpr(t0, rs); + maskb = 1ULL << (rt + 32); + tcg_gen_andi_tl(t0, t0, maskb); + bcond_compute = 1; + btgt = ctx->pc + insn_bytes + offset; + break; case OPC_BGEZ: case OPC_BGEZAL: case OPC_BGEZALS: @@ -2888,6 +3137,14 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc, MIPS_DEBUG("bne %s, %s, " TARGET_FMT_lx, regnames[rs], regnames[rt], btgt); goto not_likely; + case OPC_BBIT1: + case OPC_BBIT132: + tcg_gen_setcondi_tl(TCG_COND_NE, bcond, t0, 0); + goto not_likely; + case OPC_BBIT0: + case OPC_BBIT032: + tcg_gen_setcondi_tl(TCG_COND_EQ, bcond, t0, 0); + goto not_likely; case OPC_BNEL: tcg_gen_setcond_tl(TCG_COND_NE, bcond, t0, t1); MIPS_DEBUG("bnel %s, %s, " TARGET_FMT_lx, @@ -2983,7 +3240,42 @@ 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_orc_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_orc_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 +3355,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: @@ -11609,8 +11917,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) { env->CP0_BadVAddr = ctx->pc; @@ -11638,6 +11945,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); @@ -11863,6 +12173,58 @@ static void decode_opc (CPUState *env, DisasContext *ctx, int *is_branch) case OPC_MUL: gen_arith(env, ctx, op1, rd, rs, rt); break; +#if defined(TARGET_MIPS64) + + case OPC_DMUL: + check_mips_64(ctx); + check_insn(env, ctx, INSN_OCTEON); + gen_arith(env, ctx, op1, rd, rs, rt); + break; + case OPC_CINS: + check_mips_64(ctx); + check_insn(env, ctx, INSN_OCTEON); + gen_bitops(ctx, op1, rt, rs, sa, rd); + break; + case OPC_CINS32: + check_mips_64(ctx); + check_insn(env, ctx, INSN_OCTEON); + gen_bitops(ctx, op1, rt, rs, sa, rd); + break; + case OPC_MTM0: + case OPC_MTM1: + case OPC_MTM2: + case OPC_MTP0: + case OPC_MTP1: + case OPC_MTP2: + case OPC_VMULU: + check_mips_64(ctx); + check_insn(env, ctx, INSN_OCTEON); + gen_LMI(env, ctx, op1, rs, rt, rd); + break; + case OPC_BADDU: + check_insn(env, ctx, INSN_OCTEON); + gen_arith(env, ctx, op1, rd, rs, rt); + break; + case OPC_EXTS: + check_mips_64(ctx); + check_insn(env, ctx, INSN_OCTEON); + gen_exts(env, ctx, op1, rt, rs, sa, rd); + break; + case OPC_EXTS32: + check_mips_64(ctx); + check_insn(env, ctx, INSN_OCTEON); + gen_exts(env, ctx, op1, rt, rs, sa, rd); + break; + case OPC_SAA: + check_insn(env, ctx, INSN_OCTEON); + gen_saa(env, ctx, op1, rt, rs); + break; + case OPC_SAAD: + check_insn(env, ctx, INSN_OCTEON); + check_mips_64(ctx); + gen_saa(env, ctx, op1, rt, rs); + break; +#endif case OPC_CLO: case OPC_CLZ: check_insn(env, ctx, ISA_MIPS32); @@ -11882,13 +12244,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 (!(env->insn_flags & CPU_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: @@ -11896,7 +12269,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: @@ -11905,6 +12277,37 @@ 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 (!(env->insn_flags & CPU_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: + case OPC_SNE: + check_mips_64(ctx); + check_insn(env, ctx, INSN_OCTEON); + gen_seqsne(ctx, op1, rd, rs, rt); + break; + case OPC_SEQI: + case OPC_SNEI: + check_mips_64(ctx); + check_insn(env, ctx, INSN_OCTEON); + gen_set_imm(env, op1, rt, rs, imm10); + break; + case OPC_POP: + check_insn(env, ctx, INSN_OCTEON); + gen_pop_count(ctx, op1, rd, rs); + break; + case OPC_DPOP: + check_mips_64(ctx); + check_insn(env, ctx, INSN_OCTEON); + gen_pop_count(ctx, op1, rd, rs); + break; #endif default: /* Invalid */ MIPS_INVAL("special2"); @@ -12196,10 +12599,18 @@ static void decode_opc (CPUState *env, DisasContext *ctx, int *is_branch) break; /* COP2. */ - case OPC_LWC2: - case OPC_LDC2: - case OPC_SWC2: - case OPC_SDC2: + /* Conflicting opcodes with Cavium specific branch instructions + if cpu_model is set to Octeon these opcodes will + belong to Octeon processor */ + case OPC_LWC2: /* BBIT0 */ + case OPC_LDC2: /* BBIT032 */ + case OPC_SWC2: /* BBIT1 */ + case OPC_SDC2: /* BBIT132 */ + if (env->insn_flags & CPU_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); @@ -12588,6 +12999,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, active_tc.MPL0), "MPL0"); + mpl1 = tcg_global_mem_new(TCG_AREG0, + offsetof(CPUState, active_tc.MPL1), "MPL1"); + mpl2 = tcg_global_mem_new(TCG_AREG0, + offsetof(CPUState, active_tc.MPL2), "MPL2"); + p0 = tcg_global_mem_new(TCG_AREG0, + offsetof(CPUState, active_tc.P0), "P0"); + p1 = tcg_global_mem_new(TCG_AREG0, + offsetof(CPUState, active_tc.P1), "P1"); + p2 = tcg_global_mem_new(TCG_AREG0, + offsetof(CPUState, active_tc.P2), "P2"); bcond = tcg_global_mem_new(TCG_AREG0, offsetof(CPUState, bcond), "bcond"); btarget = tcg_global_mem_new(TCG_AREG0, diff --git a/host-utils.c b/host-utils.c index dc96123..1128698 100644 --- a/host-utils.c +++ b/host-utils.c @@ -102,4 +102,5 @@ void muls64 (uint64_t *plow, uint64_t *phigh, int64_t a, int64_t b) a, b, *phigh, *plow); #endif } + #endif /* !defined(__x86_64__) */ diff --git a/target-mips/cpu.h b/target-mips/cpu.h index 0b98d10..47e6c1f 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -171,6 +171,13 @@ struct TCState { target_ulong CP0_TCSchedule; target_ulong CP0_TCScheFBack; int32_t CP0_Debug_tcstatus; + /* Multiplier registers for Octeon */ + target_ulong MPL0; + target_ulong MPL1; + target_ulong MPL2; + target_ulong P0; + target_ulong P1; + target_ulong P2; }; typedef struct CPUMIPSState CPUMIPSState; diff --git a/target-mips/helper.h b/target-mips/helper.h index 297ab64..e892d39 100644 --- a/target-mips/helper.h +++ b/target-mips/helper.h @@ -8,7 +8,12 @@ DEF_HELPER_3(ldl, tl, tl, tl, int) DEF_HELPER_3(ldr, tl, tl, tl, int) DEF_HELPER_3(sdl, void, tl, tl, int) DEF_HELPER_3(sdr, void, tl, tl, int) +DEF_HELPER_2(v3mulu, tl, tl, tl) +DEF_HELPER_2(vmulu, tl, tl, tl) +DEF_HELPER_1(dpop, tl, tl) #endif +DEF_HELPER_1(pop, tl, tl); + DEF_HELPER_3(lwl, tl, tl, tl, int) DEF_HELPER_3(lwr, tl, tl, tl, int) DEF_HELPER_3(swl, void, tl, tl, int) diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index b8e4991..96cfbe6 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -266,7 +266,69 @@ void helper_dmultu (target_ulong arg1, target_ulong arg2) { mulu64(&(env->active_tc.LO[0]), &(env->active_tc.HI[0]), arg1, arg2); } +static void addc(uint64_t res[], uint64_t a, int i) +{ + uint64_t c = res[i]; + for (; i < 4; i++) { + res[i] = c + a; + if (res[i] < a) { + c = 1; + a = res[i+1]; + } else + break; + } +} +target_ulong helper_v3mulu(target_ulong arg1, target_ulong arg2) +{ + uint64_t hi, lo, res[4]; + int i; + for (i = 0; i < 4; i++) { + res[i] = 0; + } + mulu64(&res[0], &res[1], env->active_tc.MPL0, arg1); + mulu64(&lo, &hi, env->active_tc.MPL1, arg1); + res[1] = res[1] + lo; + if (res[1] < lo) + res[2]++; + res[2] = res[2] + hi; + if (res[2] < hi) + res[3]++; + mulu64(&lo, &hi, env->active_tc.MPL2, arg1); + res[2] = res[2] + lo; + if (res[2] < lo) + res[3]++; + res[3] = res[3] + hi; + addc(res, arg2, 0); + addc(res, env->active_tc.P0, 0); + addc(res, env->active_tc.P1, 1); + addc(res, env->active_tc.P2, 2); + env->active_tc.P0 = res[1]; + env->active_tc.P1 = res[2]; + env->active_tc.P2 = res[3]; + return res[0]; +} +target_ulong helper_vmulu(target_ulong arg1, target_ulong arg2) +{ + uint64_t hi, lo; + mulu64(&lo, &hi, env->active_tc.MPL0, arg1); + lo = lo + arg2; + if (lo < arg2) + hi++; + lo = lo + env->active_tc.P0; + if (lo < env->active_tc.P0) + hi++; + env->active_tc.P0 = hi; + return lo; +} +target_ulong helper_dpop(target_ulong arg) +{ + return ctpop64(arg); +} #endif +target_ulong helper_pop(target_ulong arg) +{ + return ctpop32((uint32_t)arg); +} #ifndef CONFIG_USER_ONLY diff --git a/target-mips/translate.c b/target-mips/translate.c index c88c3f9..cb431a8 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -70,6 +70,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(for upper 32 bits) */ + OPC_BBIT0 = (0x32 << 26), /* jump on bit clear, cavium specific */ + OPC_BBIT032 = (0x36 << 26), /* jump on bit clear(for upper 32 bits) */ OPC_BEQL = (0x14 << 26), OPC_BNE = (0x05 << 26),