diff --git a/target/mips/mips-defs.h b/target/mips/mips-defs.h index 047554ee450..61f8eefa964 100644 --- a/target/mips/mips-defs.h +++ b/target/mips/mips-defs.h @@ -48,6 +48,7 @@ #define ASE_MSA 0x01000000 /* Chip specific instructions. */ +#define INSN_OCTEON 0x10000000 #define INSN_LOONGSON2E 0x20000000 #define INSN_LOONGSON2F 0x40000000 #define INSN_VR54XX 0x80000000 diff --git a/target/mips/translate.c b/target/mips/translate.c index c2b4a93ae82..92f303ced23 100644 --- a/target/mips/translate.c +++ b/target/mips/translate.c @@ -15304,7 +15304,9 @@ static void gen_mipsdsp_ld(DisasContext *ctx, uint32_t opc, { TCGv t0; - check_dsp(ctx); + if ((ctx->insn_flags & INSN_OCTEON) == 0){ + check_dsp(ctx); + } t0 = tcg_temp_new(); if (base == 0) { @@ -19230,6 +19232,849 @@ static void gen_msa(CPUMIPSState *env, DisasContext *ctx) } +#if defined(TARGET_MIPS64) +#define INFO(msg) \ + fprintf(stderr, "info: %s:%d: ", __FILE__, __LINE__); \ + fprintf(stderr, "%s", msg); + +typedef struct { + int set; + int rs; + int offset; + int p; +} arg_decode0; + +typedef struct { + int rs; + int rt; + int rd; +} arg_decode1; + +typedef struct { + int rs; + int rt; + int lenm1; + int p; +} arg_decode2; + +typedef struct { + int rs; + int rd; + int dw; +} arg_decode3; + +typedef struct { + int rs; + int rt; + int rd; + int ne; +} arg_decode4; + +typedef struct { + int rs; + int rt; + int imm; + int ne; +} arg_decode5; + +typedef struct { + int base; + int rt; +} arg_decode6; + +typedef arg_decode0 arg_BBIT; +static bool trans_BBIT(DisasContext *ctx, arg_BBIT *a); +typedef arg_decode1 arg_BADDU; +static bool trans_BADDU(DisasContext *ctx, arg_BADDU *a); +typedef arg_decode1 arg_DMUL; +static bool trans_DMUL(DisasContext *ctx, arg_DMUL *a); +typedef arg_decode2 arg_EXTS; +static bool trans_EXTS(DisasContext *ctx, arg_EXTS *a); +typedef arg_decode2 arg_CINS; +static bool trans_CINS(DisasContext *ctx, arg_CINS *a); +typedef arg_decode3 arg_POP; +static bool trans_POP(DisasContext *ctx, arg_POP *a); +typedef arg_decode4 arg_SEQNE; +static bool trans_SEQNE(DisasContext *ctx, arg_SEQNE *a); +typedef arg_decode5 arg_SEQNEI; +static bool trans_SEQNEI(DisasContext *ctx, arg_SEQNEI *a); +typedef arg_decode6 arg_SAA; +static bool trans_SAA(DisasContext *ctx, arg_SAA *a); +typedef arg_decode6 arg_SAAD; +static bool trans_SAAD(DisasContext *ctx, arg_SAAD *a); +typedef arg_decode1 arg_LAI; +static bool trans_LAI(DisasContext *ctx, arg_LAI *a); +typedef arg_decode1 arg_LAID; +static bool trans_LAID(DisasContext *ctx, arg_LAID *a); +typedef arg_decode1 arg_LAD; +static bool trans_LAD(DisasContext *ctx, arg_LAD *a); +typedef arg_decode1 arg_LADD; +static bool trans_LADD(DisasContext *ctx, arg_LADD *a); +typedef arg_decode1 arg_LAS; +static bool trans_LAS(DisasContext *ctx, arg_LAS *a); +typedef arg_decode1 arg_LASD; +static bool trans_LASD(DisasContext *ctx, arg_LASD *a); +typedef arg_decode1 arg_LAC; +static bool trans_LAC(DisasContext *ctx, arg_LAC *a); +typedef arg_decode1 arg_LACD; +static bool trans_LACD(DisasContext *ctx, arg_LACD *a); +typedef arg_decode1 arg_LAA; +static bool trans_LAA(DisasContext *ctx, arg_LAA *a); +typedef arg_decode1 arg_LAAD; +static bool trans_LAAD(DisasContext *ctx, arg_LAAD *a); +typedef arg_decode1 arg_LAW; +static bool trans_LAW(DisasContext *ctx, arg_LAW *a); +typedef arg_decode1 arg_LAWD; +static bool trans_LAWD(DisasContext *ctx, arg_LAWD *a); +typedef arg_decode1 arg_LWX; +static bool trans_LWX(DisasContext *ctx, arg_LWX *a); +typedef arg_decode1 arg_LHX; +static bool trans_LHX(DisasContext *ctx, arg_LHX *a); +typedef arg_decode1 arg_LDX; +static bool trans_LDX(DisasContext *ctx, arg_LDX *a); +typedef arg_decode1 arg_LBUX; +static bool trans_LBUX(DisasContext *ctx, arg_LBUX *a); +typedef arg_decode1 arg_LWUX; +static bool trans_LWUX(DisasContext *ctx, arg_LWUX *a); +typedef arg_decode1 arg_LHUX; +static bool trans_LHUX(DisasContext *ctx, arg_LHUX *a); +typedef arg_decode1 arg_LBX; +static bool trans_LBX(DisasContext *ctx, arg_LBX *a); + +static void decode_extract_bitfield(DisasContext *ctx, arg_decode2 *a, uint32_t insn) +{ + a->lenm1 = extract32(insn, 11, 5); + a->rt = extract32(insn, 16, 5); + a->p = deposit32(extract32(insn, 6, 5), 5, 27, extract32(insn, 0, 1)); + a->rs = extract32(insn, 21, 5); +} + +static void decode_extract_decode_Fmt_0(DisasContext *ctx, arg_decode0 *a, uint32_t insn) +{ + a->offset = sextract32(insn, 0, 16); + a->set = extract32(insn, 29, 1); + a->p = deposit32(extract32(insn, 16, 5), 5, 27, extract32(insn, 28, 1)); + a->rs = extract32(insn, 21, 5); +} + +static void decode_extract_decode_Fmt_3(DisasContext *ctx, arg_decode3 *a, uint32_t insn) +{ + a->dw = extract32(insn, 0, 1); + a->rd = extract32(insn, 11, 5); + a->rs = extract32(insn, 21, 5); +} + +static void decode_extract_decode_Fmt_4(DisasContext *ctx, arg_decode4 *a, uint32_t insn) +{ + a->rt = extract32(insn, 16, 5); + a->rd = extract32(insn, 11, 5); + a->ne = extract32(insn, 0, 1); + a->rs = extract32(insn, 21, 5); +} + +static void decode_extract_decode_Fmt_5(DisasContext *ctx, arg_decode5 *a, uint32_t insn) +{ + a->imm = sextract32(insn, 6, 10); + a->rt = extract32(insn, 16, 5); + a->ne = extract32(insn, 0, 1); + a->rs = extract32(insn, 21, 5); +} + +static void decode_extract_decode_Fmt_6(DisasContext *ctx, arg_decode6 *a, uint32_t insn) +{ + a->rt = extract32(insn, 16, 5); + a->base = extract32(insn, 21, 5); +} + +static void decode_extract_r3(DisasContext *ctx, arg_decode1 *a, uint32_t insn) +{ + a->rt = extract32(insn, 16, 5); + a->rd = extract32(insn, 11, 5); + a->rs = extract32(insn, 21, 5); +} + +static bool trans_BBIT(DisasContext *ctx, arg_BBIT *a) +{ + TCGv p; + if (ctx->hflags & MIPS_HFLAG_BMASK) { + LOG_DISAS("Branch in delay / forbidden slot at PC 0x" + TARGET_FMT_lx "\n", ctx->pc); + generate_exception_end(ctx, EXCP_RI); + return true; + } + + /* Load needed operands */ + TCGv t0 = tcg_temp_new(); + gen_load_gpr(t0, a->rs); + + p = tcg_const_tl(1ULL << a->p); + if (a->set) { + tcg_gen_and_tl(bcond, p, t0); + } else { + tcg_gen_andc_tl(bcond, p, t0); + } + + ctx->hflags |= MIPS_HFLAG_BC; + ctx->btarget = ctx->pc + 4 + a->offset * 4; + ctx->hflags |= MIPS_HFLAG_BDS32; + + tcg_temp_free(t0); + return true; +} + +static bool trans_BADDU(DisasContext *ctx, arg_BADDU *a) +{ + TCGv t0, t1; + if (a->rt == 0) + { + /* nop */ + return true; + } + + t0 = tcg_temp_new(); + t1 = tcg_temp_new(); + gen_load_gpr(t0, a->rs); + gen_load_gpr(t1, a->rt); + + tcg_gen_add_tl(t0, t0, t1); + tcg_gen_andi_i64(cpu_gpr[a->rd], t0, 0xff); + + tcg_temp_free(t0); + tcg_temp_free(t1); + + return true; +} + +static bool trans_DMUL(DisasContext *ctx, arg_DMUL *a) +{ + TCGv t0, t1; + + if (a->rt == 0) { + /* nop */ + return true; + } + + t0 = tcg_temp_new(); + t1 = tcg_temp_new(); + gen_load_gpr(t0, a->rs); + gen_load_gpr(t1, a->rt); + + tcg_gen_mul_i64(cpu_gpr[a->rd], t0, t1); + + tcg_temp_free(t0); + tcg_temp_free(t1); + + return true; +} + +static bool trans_EXTS(DisasContext *ctx, arg_EXTS *a) +{ + TCGv t0; + + if (a->rt == 0) { + /* nop */ + return true; + } + + t0 = tcg_temp_new(); + gen_load_gpr(t0, a->rs); + tcg_gen_sextract_tl(t0, t0, a->p, a->lenm1 + 1); + gen_store_gpr(t0, a->rt); + tcg_temp_free(t0); + + return true; +} + +static bool trans_CINS(DisasContext *ctx, arg_CINS *a) +{ + TCGv t0; + + if (a->rt == 0) { + /* nop */ + return true; + } + + t0 = tcg_temp_new(); + gen_load_gpr(t0, a->rs); + tcg_gen_deposit_z_tl(t0, t0, a->p, a->lenm1 + 1); + gen_store_gpr(t0, a->rt); + tcg_temp_free(t0); + + return true; +} + +static bool trans_POP(DisasContext *ctx, arg_POP *a) +{ + TCGv t0; + + if (a->rd == 0) { + /* nop */ + return true; + } + + t0 = tcg_temp_new(); + gen_load_gpr(t0, a->rs); + if (!a->dw) { + tcg_gen_andi_i64(t0, t0, 0xffffffff); + } + tcg_gen_ctpop_tl(t0, t0); + gen_store_gpr(t0, a->rd); + tcg_temp_free(t0); + + return true; +} + +static bool trans_SEQNE(DisasContext *ctx, arg_SEQNE *a) +{ + TCGv t0, t1; + + if (a->rd == 0) { + /* nop */ + return true; + } + + t0 = tcg_temp_new(); + t1 = tcg_temp_new(); + + gen_load_gpr(t0, a->rs); + gen_load_gpr(t1, a->rt); + + if (a->ne) { + tcg_gen_setcond_tl(TCG_COND_NE, cpu_gpr[a->rd], t1, t0); + } else { + tcg_gen_setcond_tl(TCG_COND_EQ, cpu_gpr[a->rd], t1, t0); + } + + tcg_temp_free(t0); + tcg_temp_free(t1); + + return true; +} + +static bool trans_SEQNEI(DisasContext *ctx, arg_SEQNEI *a) +{ + TCGv t0; + + if (a->rt == 0) { + /* nop */ + return true; + } + + t0 = tcg_temp_new(); + + gen_load_gpr(t0, a->rs); + + /* Sign-extend to 64 bit value */ + target_ulong imm = a->imm; + if (a->ne) { + tcg_gen_setcondi_tl(TCG_COND_NE, cpu_gpr[a->rt], t0, imm); + } else { + tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_gpr[a->rt], t0, imm); + } + + tcg_temp_free(t0); + + return true; +} + + +/* + * Octeon+ + * https://sourceware.org/legacy-ml/binutils/2011-11/msg00085.html + */ +static bool trans_SAA(DisasContext *ctx, arg_SAA *a) +{ + TCGv t0 = tcg_temp_new(); + tcg_gen_qemu_ld_tl(t0, cpu_gpr[a->base], ctx->mem_idx, MO_TEUL | + ctx->default_tcg_memop_mask); + tcg_gen_add_tl(t0, t0, cpu_gpr[a->rt]); + + tcg_gen_qemu_st_tl(t0, cpu_gpr[a->base], ctx->mem_idx, MO_TEUL | + ctx->default_tcg_memop_mask); + return true; +} + +static bool trans_SAAD(DisasContext *ctx, arg_SAAD *a) +{ + TCGv_i64 t0 = tcg_temp_new_i64(); + tcg_gen_qemu_ld_tl(t0, cpu_gpr[a->base], ctx->mem_idx, MO_TEQ | + ctx->default_tcg_memop_mask); + tcg_gen_add_tl(t0, t0, cpu_gpr[a->rt]); + + tcg_gen_qemu_st_tl(t0, cpu_gpr[a->base], ctx->mem_idx, MO_TEQ | + ctx->default_tcg_memop_mask); + return true; +} + +/* + * Octeon2 + * +ttps://chromium.googlesource.com/chromiumos/third_party/gdb/+/refs/heads/master/opcodes/mips-opc.c + * https://github.com/MarvellEmbeddedProcessors/Octeon-Toolchain + * https://bugs.kde.org/show_bug.cgi?id=326444 + * https://gcc.gnu.org/legacy-ml/gcc-patches/2011-12/msg01134.html + */ +static bool trans_LAI(DisasContext *ctx, arg_LAI *a) +{ + TCGv t0 = tcg_temp_new(); + tcg_gen_qemu_ld_tl(t0, cpu_gpr[a->rs], ctx->mem_idx, MO_TEUL | + ctx->default_tcg_memop_mask); + gen_store_gpr(t0, a->rd); + tcg_gen_addi_tl(t0, t0, 1); + + tcg_gen_qemu_st_tl(t0, cpu_gpr[a->rs], ctx->mem_idx, MO_TEUL | + ctx->default_tcg_memop_mask); + return true; +} + +static bool trans_LAID(DisasContext *ctx, arg_LAID *a) +{ + TCGv_i64 t0 = tcg_temp_new_i64(); + tcg_gen_qemu_ld_tl(t0, cpu_gpr[a->rs], ctx->mem_idx, MO_TEQ | + ctx->default_tcg_memop_mask); + gen_store_gpr(t0, a->rd); + tcg_gen_addi_tl(t0, t0, 1); + + tcg_gen_qemu_st_tl(t0, cpu_gpr[a->rs], ctx->mem_idx, MO_TEQ | + ctx->default_tcg_memop_mask); + return true; +} + +static bool trans_LAD(DisasContext *ctx, arg_LAD *a) +{ + TCGv t0 = tcg_temp_new(); + tcg_gen_qemu_ld_tl(t0, cpu_gpr[a->rs], ctx->mem_idx, MO_TEUL | + ctx->default_tcg_memop_mask); + gen_store_gpr(t0, a->rd); + tcg_gen_subi_tl(t0, t0, 1); + + tcg_gen_qemu_st_tl(t0, cpu_gpr[a->rs], ctx->mem_idx, MO_TEUL | + ctx->default_tcg_memop_mask); + return true; +} + +static bool trans_LADD(DisasContext *ctx, arg_LADD *a) +{ + TCGv_i64 t0 = tcg_temp_new_i64(); + tcg_gen_qemu_ld_tl(t0, cpu_gpr[a->rs], ctx->mem_idx, MO_TEQ | + ctx->default_tcg_memop_mask); + gen_store_gpr(t0, a->rd); + tcg_gen_subi_tl(t0, t0, 1); + + tcg_gen_qemu_st_tl(t0, cpu_gpr[a->rs], ctx->mem_idx, MO_TEQ | + ctx->default_tcg_memop_mask); + return true; +} +/* Load Atomic Set Word - LAS; Cavium OCTEON2 */ +static bool trans_LAS(DisasContext *ctx, arg_LAS *a) +{ + TCGv t0 = tcg_temp_new(); + tcg_gen_qemu_ld_tl(t0, cpu_gpr[a->rs], ctx->mem_idx, MO_TEUL | + ctx->default_tcg_memop_mask); + gen_store_gpr(t0, a->rd); + tcg_gen_movi_tl(t0, 0xffffffff); + + tcg_gen_qemu_st_tl(t0, cpu_gpr[a->rs], ctx->mem_idx, MO_TEUL | + ctx->default_tcg_memop_mask); + + return true; +} +/* Load Atomic Set Doubleword - LASD; Cavium OCTEON2 */ +static bool trans_LASD(DisasContext *ctx, arg_LASD *a) +{ + TCGv_i64 t0 = tcg_temp_new_i64(); + tcg_gen_qemu_ld_tl(t0, cpu_gpr[a->rs], ctx->mem_idx, MO_TEQ | + ctx->default_tcg_memop_mask); + gen_store_gpr(t0, a->rd); + tcg_gen_movi_tl(t0, 0xffffffffffffffffULL); + + tcg_gen_qemu_st_tl(t0, cpu_gpr[a->rs], ctx->mem_idx, MO_TEQ | + ctx->default_tcg_memop_mask); + return true; +} +/* Load Atomic Clear Word - LAC; Cavium OCTEON2 */ +static bool trans_LAC(DisasContext *ctx, arg_LAC *a) +{ + TCGv t0 = tcg_temp_new(); + tcg_gen_qemu_ld_tl(t0, cpu_gpr[a->rs], ctx->mem_idx, MO_TEUL | + ctx->default_tcg_memop_mask); + gen_store_gpr(t0, a->rd); + tcg_gen_movi_tl(t0, 0); + + tcg_gen_qemu_st_tl(t0, cpu_gpr[a->rs], ctx->mem_idx, MO_TEUL | + ctx->default_tcg_memop_mask); + return true; +} +/* Load Atomic Clear Doubleword - LACD; Cavium OCTEON2 */ +static bool trans_LACD(DisasContext *ctx, arg_LACD *a) +{ + TCGv_i64 t0 = tcg_temp_new_i64(); + tcg_gen_qemu_ld_tl(t0, cpu_gpr[a->rs], ctx->mem_idx, MO_TEQ | + ctx->default_tcg_memop_mask); + gen_store_gpr(t0, a->rd); + tcg_gen_movi_tl(t0, 0xffffffffffffffffULL); + + tcg_gen_qemu_st_tl(t0, cpu_gpr[a->rs], ctx->mem_idx, MO_TEQ | + ctx->default_tcg_memop_mask); + return true; +} + +/* Load Atomic Add Word - LAA; Cavium OCTEON2 */ +static bool trans_LAA(DisasContext *ctx, arg_LAA *a) +{ + TCGv t0 = tcg_temp_new(); + tcg_gen_qemu_ld_tl(t0, cpu_gpr[a->rs], ctx->mem_idx, MO_TEUL | + ctx->default_tcg_memop_mask); + gen_store_gpr(t0, a->rd); + tcg_gen_add_tl(t0, t0, cpu_gpr[a->rt]); + + tcg_gen_qemu_st_tl(t0, cpu_gpr[a->rs], ctx->mem_idx, MO_TEUL | + ctx->default_tcg_memop_mask); + return true; +} + +/* Load Atomic Add Doubleword - LAAD; Cavium OCTEON2 */ +static bool trans_LAAD(DisasContext *ctx, arg_LAAD *a) +{ + TCGv_i64 t0 = tcg_temp_new_i64(); + tcg_gen_qemu_ld_tl(t0, cpu_gpr[a->rs], ctx->mem_idx, MO_TEQ | + ctx->default_tcg_memop_mask); + gen_store_gpr(t0, a->rd); + tcg_gen_add_tl(t0, t0, cpu_gpr[a->rt]); + + tcg_gen_qemu_st_tl(t0, cpu_gpr[a->rs], ctx->mem_idx, MO_TEQ | + ctx->default_tcg_memop_mask); + return true; +} +/* Load Atomic Swap Word - LAW; Cavium OCTEON2 */ +static bool trans_LAW(DisasContext *ctx, arg_LAW *a) +{ + TCGv t0 = tcg_temp_new(); + tcg_gen_qemu_ld_tl(t0, cpu_gpr[a->rs], ctx->mem_idx, MO_TEUL | + ctx->default_tcg_memop_mask); + gen_store_gpr(t0, a->rd); + tcg_gen_mov_tl(t0, cpu_gpr[a->rt]); + + tcg_gen_qemu_st_tl(t0, cpu_gpr[a->rs], ctx->mem_idx, MO_TEUL | + ctx->default_tcg_memop_mask); + return true; +} + +static bool trans_LAWD(DisasContext *ctx, arg_LAWD *a) +{ + TCGv_i64 t0 = tcg_temp_new_i64(); + tcg_gen_qemu_ld_tl(t0, cpu_gpr[a->rs], ctx->mem_idx, MO_TEQ | + ctx->default_tcg_memop_mask); + gen_store_gpr(t0, a->rd); + tcg_gen_mov_tl(t0, cpu_gpr[a->rt]); + + tcg_gen_qemu_st_tl(t0, cpu_gpr[a->rs], ctx->mem_idx, MO_TEQ | + ctx->default_tcg_memop_mask); + return true; +} + + +static bool trans_LWX(DisasContext *ctx, arg_LWX *a) +{ + TCGv t0 = tcg_temp_new(); + gen_op_addr_add(ctx, t0, cpu_gpr[a->rs], cpu_gpr[a->rt]); + + tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TESL | + ctx->default_tcg_memop_mask); + + /* on mips64, 32 extend to 64 */ + tcg_gen_ext32s_tl(cpu_gpr[a->rd], t0); + return true; +} + +static bool trans_LHX(DisasContext *ctx, arg_LHX *a) +{ + TCGv t0 = tcg_temp_new(); + gen_op_addr_add(ctx, t0, cpu_gpr[a->rs], cpu_gpr[a->rt]); + + tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TESW | + ctx->default_tcg_memop_mask); + + /* 16 extend to 32/64 */ + tcg_gen_ext16s_tl(cpu_gpr[a->rd], t0); + return true; +} + +static bool trans_LDX(DisasContext *ctx, arg_LDX *a) +{ + TCGv_i64 t0 = tcg_temp_new_i64(); + gen_op_addr_add(ctx, t0, cpu_gpr[a->rs], cpu_gpr[a->rt]); + + tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEQ | + ctx->default_tcg_memop_mask); + /* not extend */ + gen_store_gpr(t0, a->rd); + return true; +} + +static bool trans_LBUX(DisasContext *ctx, arg_LBUX *a) +{ + TCGv t0 = tcg_temp_new(); + gen_op_addr_add(ctx, t0, cpu_gpr[a->rs], cpu_gpr[a->rt]); + + tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_UB | + ctx->default_tcg_memop_mask); + + tcg_gen_ext8u_tl(cpu_gpr[a->rd], t0); + return true; +} + +static bool trans_LWUX(DisasContext *ctx, arg_LWUX *a) +{ + TCGv t0 = tcg_temp_new(); + gen_op_addr_add(ctx, t0, cpu_gpr[a->rs], cpu_gpr[a->rt]); + + tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEUL | + ctx->default_tcg_memop_mask); + + tcg_gen_ext32u_tl(cpu_gpr[a->rd], t0); + return true; +} + +static bool trans_LHUX(DisasContext *ctx, arg_LHUX *a) +{ + TCGv t0 = tcg_temp_new(); + gen_op_addr_add(ctx, t0, cpu_gpr[a->rs], cpu_gpr[a->rt]); + + tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEUW | + ctx->default_tcg_memop_mask); + + tcg_gen_ext16u_tl(cpu_gpr[a->rd], t0); + return true; +} + +static bool trans_LBX(DisasContext *ctx, arg_LBX *a) +{ + TCGv t0 = tcg_temp_new(); + gen_op_addr_add(ctx, t0, cpu_gpr[a->rs], cpu_gpr[a->rt]); + + tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_SB | + ctx->default_tcg_memop_mask); + + tcg_gen_ext8s_tl(cpu_gpr[a->rd], t0); + return true; +} + +static bool decode_octeon(DisasContext *ctx, uint32_t insn) +{ + union { + arg_decode0 f_decode0; + arg_decode1 f_decode1; + arg_decode2 f_decode2; + arg_decode3 f_decode3; + arg_decode4 f_decode4; + arg_decode5 f_decode5; + arg_decode6 f_decode6; + } u; + + switch (insn & 0xcc000000u) { + case 0x40000000: + /* 01..00.. ........ ........ ........ */ + switch (insn & 0x3000003e) { + case 0x30000002: + /* 011100.. ........ ........ ..00001. */ + decode_extract_r3(ctx, &u.f_decode1, insn); + switch (insn & 0x000007c1) { + case 0x00000001: + /* 011100.. ........ .....000 00000011 */ + /* target/mips/tcg/octeon.decode:36 */ + if (trans_DMUL(ctx, &u.f_decode1)) return true; + break; + } + break; + case 0x30000018: + /* 011100.. ........ ........ ..01100. */ + decode_extract_decode_Fmt_6(ctx, &u.f_decode6, insn); + switch (insn & 0x0000ffc1) { + case 0x00000000: + /* 011100.. ........ 00000000 00011000 */ + /* target/mips/tcg/octeon.decode:47 */ + if (trans_SAA(ctx, &u.f_decode6)) return true; + break; + case 0x00000001: + /* 011100.. ........ 00000000 00011001 */ + /* target/mips/tcg/octeon.decode:48 */ + if (trans_SAAD(ctx, &u.f_decode6)) return true; + break; + } + break; + case 0x3000001e: + /* 011100.. ........ ........ ..01111. */ + decode_extract_r3(ctx, &u.f_decode1, insn); + switch (insn & 0x000007c1) { + case 0x00000081: + /* 011100.. ........ .....000 10011111 */ + /* target/mips/tcg/octeon.decode:50 */ + if (trans_LAI(ctx, &u.f_decode1)) return true; + break; + case 0x000000c1: + /* 011100.. ........ .....000 11011111 */ + /* target/mips/tcg/octeon.decode:51 */ + if (trans_LAID(ctx, &u.f_decode1)) return true; + break; + case 0x00000181: + /* 011100.. ........ .....001 10011111 */ + /* target/mips/tcg/octeon.decode:52 */ + if (trans_LAD(ctx, &u.f_decode1)) return true; + break; + case 0x000001c1: + /* 011100.. ........ .....001 11011111 */ + /* target/mips/tcg/octeon.decode:53 */ + if (trans_LADD(ctx, &u.f_decode1)) return true; + break; + case 0x00000281: + /* 011100.. ........ .....010 10011111 */ + /* target/mips/tcg/octeon.decode:54 */ + if (trans_LAS(ctx, &u.f_decode1)) return true; + break; + case 0x000002c1: + /* 011100.. ........ .....010 11011111 */ + /* target/mips/tcg/octeon.decode:55 */ + if (trans_LASD(ctx, &u.f_decode1)) return true; + break; + case 0x00000381: + /* 011100.. ........ .....011 10011111 */ + /* target/mips/tcg/octeon.decode:56 */ + if (trans_LAC(ctx, &u.f_decode1)) return true; + break; + case 0x000003c1: + /* 011100.. ........ .....011 11011111 */ + /* target/mips/tcg/octeon.decode:57 */ + if (trans_LACD(ctx, &u.f_decode1)) return true; + break; + case 0x00000481: + /* 011100.. ........ .....100 10011111 */ + /* target/mips/tcg/octeon.decode:58 */ + if (trans_LAA(ctx, &u.f_decode1)) return true; + break; + case 0x000004c1: + /* 011100.. ........ .....100 11011111 */ + /* target/mips/tcg/octeon.decode:59 */ + if (trans_LAAD(ctx, &u.f_decode1)) return true; + break; + case 0x00000581: + /* 011100.. ........ .....101 10011111 */ + /* target/mips/tcg/octeon.decode:60 */ + if (trans_LAW(ctx, &u.f_decode1)) return true; + break; + case 0x000005c1: + /* 011100.. ........ .....101 11011111 */ + /* target/mips/tcg/octeon.decode:61 */ + if (trans_LAWD(ctx, &u.f_decode1)) return true; + break; + } + break; + case 0x30000028: + /* 011100.. ........ ........ ..10100. */ + decode_extract_r3(ctx, &u.f_decode1, insn); + switch (insn & 0x000007c1) { + case 0x00000000: + /* 011100.. ........ .....000 00101000 */ + /* target/mips/tcg/octeon.decode:35 */ + if (trans_BADDU(ctx, &u.f_decode1)) return true; + break; + } + break; + case 0x3000002a: + /* 011100.. ........ ........ ..10101. */ + decode_extract_decode_Fmt_4(ctx, &u.f_decode4, insn); + switch ((insn >> 6) & 0x1f) { + case 0x0: + /* 011100.. ........ .....000 0010101. */ + /* target/mips/tcg/octeon.decode:40 */ + if (trans_SEQNE(ctx, &u.f_decode4)) return true; + break; + } + break; + case 0x3000002c: + /* 011100.. ........ ........ ..10110. */ + decode_extract_decode_Fmt_3(ctx, &u.f_decode3, insn); + switch (insn & 0x001f07c0) { + case 0x00000000: + /* 011100.. ...00000 .....000 0010110. */ + /* target/mips/tcg/octeon.decode:39 */ + if (trans_POP(ctx, &u.f_decode3)) return true; + break; + } + break; + case 0x3000002e: + /* 011100.. ........ ........ ..10111. */ + /* target/mips/tcg/octeon.decode:41 */ + decode_extract_decode_Fmt_5(ctx, &u.f_decode5, insn); + if (trans_SEQNEI(ctx, &u.f_decode5)) return true; + break; + case 0x30000032: + /* 011100.. ........ ........ ..11001. */ + /* target/mips/tcg/octeon.decode:38 */ + decode_extract_bitfield(ctx, &u.f_decode2, insn); + if (trans_CINS(ctx, &u.f_decode2)) return true; + break; + case 0x3000003a: + /* 011100.. ........ ........ ..11101. */ + /* target/mips/tcg/octeon.decode:37 */ + decode_extract_bitfield(ctx, &u.f_decode2, insn); + if (trans_EXTS(ctx, &u.f_decode2)) return true; + break; + } + break; + case 0x4c000000: + /* 01..11.. ........ ........ ........ */ + decode_extract_r3(ctx, &u.f_decode1, insn); + switch (insn & 0x300007ff) { + case 0x3000000a: + /* 011111.. ........ .....000 00001010 */ + /* target/mips/tcg/octeon.decode:71 */ + if (trans_LWX(ctx, &u.f_decode1)) return true; + break; + case 0x3000010a: + /* 011111.. ........ .....001 00001010 */ + /* target/mips/tcg/octeon.decode:72 */ + if (trans_LHX(ctx, &u.f_decode1)) return true; + break; + case 0x3000018a: + /* 011111.. ........ .....001 10001010 */ + /* target/mips/tcg/octeon.decode:74 */ + if (trans_LBUX(ctx, &u.f_decode1)) return true; + break; + case 0x3000020a: + /* 011111.. ........ .....010 00001010 */ + /* target/mips/tcg/octeon.decode:73 */ + if (trans_LDX(ctx, &u.f_decode1)) return true; + break; + case 0x3000040a: + /* 011111.. ........ .....100 00001010 */ + /* target/mips/tcg/octeon.decode:75 */ + if (trans_LWUX(ctx, &u.f_decode1)) return true; + break; + case 0x3000050a: + /* 011111.. ........ .....101 00001010 */ + /* target/mips/tcg/octeon.decode:76 */ + if (trans_LHUX(ctx, &u.f_decode1)) return true; + break; + case 0x3000058a: + /* 011111.. ........ .....101 10001010 */ + /* target/mips/tcg/octeon.decode:77 */ + if (trans_LBX(ctx, &u.f_decode1)) return true; + break; + } + break; + case 0xc8000000u: + /* 11..10.. ........ ........ ........ */ + /* target/mips/tcg/octeon.decode:15 */ + decode_extract_decode_Fmt_0(ctx, &u.f_decode0, insn); + if (trans_BBIT(ctx, &u.f_decode0)) return true; + break; + } + return false; +} + +#endif + static void decode_opc(CPUMIPSState *env, DisasContext *ctx) { int32_t offset; @@ -19260,6 +20105,20 @@ static void decode_opc(CPUMIPSState *env, DisasContext *ctx) rd = (ctx->opcode >> 11) & 0x1f; sa = (ctx->opcode >> 6) & 0x1f; imm = (int16_t)ctx->opcode; + +#if defined(TARGET_MIPS64) + if ((ctx->insn_flags & INSN_OCTEON) != 0){ + // printf("is octeon\n"); + if (decode_octeon(ctx, ctx->opcode)) + { + // printf("decoded octeon insn\n"); + return; + } + }else{ + // printf("isn't octeon " "\n", ctx->insn_flags); + } +#endif + switch (op) { case OPC_SPECIAL: decode_opc_special(env, ctx); diff --git a/target/mips/translate_init.c b/target/mips/translate_init.c index 6ae23e476f7..92186aaa5c0 100644 --- a/target/mips/translate_init.c +++ b/target/mips/translate_init.c @@ -647,6 +647,34 @@ static const mips_def_t mips_defs[] = .insn_flags = CPU_MIPS64R2 | ASE_MIPS3D, .mmu_type = MMU_TYPE_R4000, }, + { + /* A generic CPU providing MIPS64 Release 2 features. + FIXME: Eventually this should be replaced by a real CPU model. */ + .name = "MIPS64R2-octeon", + .CP0_PRid = 0x00010000, + .CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR) | (0x2 << CP0C0_AT) | + (MMU_TYPE_R4000 << CP0C0_MT), + .CP0_Config1 = MIPS_CONFIG1 | (1 << CP0C1_FP) | (63 << CP0C1_MMU) | + (2 << CP0C1_IS) | (4 << CP0C1_IL) | (3 << CP0C1_IA) | + (2 << CP0C1_DS) | (4 << CP0C1_DL) | (3 << CP0C1_DA) | + (1 << CP0C1_PC) | (1 << CP0C1_WR) | (1 << CP0C1_EP), + .CP0_Config2 = MIPS_CONFIG2, + .CP0_Config3 = MIPS_CONFIG3 | (1 << CP0C3_LPA), + .CP0_LLAddr_rw_bitmask = 0, + .CP0_LLAddr_shift = 0, + .SYNCI_Step = 32, + .CCRes = 2, + .CP0_Status_rw_bitmask = 0x36FBFFFF, + .CP1_fcr0 = (1 << FCR0_F64) | (1 << FCR0_3D) | (1 << FCR0_PS) | + (1 << FCR0_L) | (1 << FCR0_W) | (1 << FCR0_D) | + (1 << FCR0_S) | (0x00 << FCR0_PRID) | (0x0 << FCR0_REV), + .CP1_fcr31 = 0, + .CP1_fcr31_rw_bitmask = 0xFF83FFFF, + .SEGBITS = 42, + .PABITS = 36, + .insn_flags = CPU_MIPS64R2 | INSN_OCTEON | ASE_MIPS3D, + .mmu_type = MMU_TYPE_R4000, + }, { .name = "5KEc", .CP0_PRid = 0x00018900, @@ -800,6 +828,34 @@ static const mips_def_t mips_defs[] = .insn_flags = CPU_MIPS64R2 | ASE_DSP | ASE_DSPR2, .mmu_type = MMU_TYPE_R4000, }, + { + /* + * Octeon 68xx with MIPS64 Cavium Octeon features. + */ + .name = "Octeon68XX", + .CP0_PRid = 0x000D9100, + .CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR) | (0x2 << CP0C0_AT) | + (MMU_TYPE_R4000 << CP0C0_MT), + .CP0_Config1 = MIPS_CONFIG1 | (0x3F << CP0C1_MMU) | + (1 << CP0C1_IS) | (4 << CP0C1_IL) | (1 << CP0C1_IA) | + (1 << CP0C1_DS) | (4 << CP0C1_DL) | (1 << CP0C1_DA) | + (1 << CP0C1_PC) | (1 << CP0C1_WR) | (1 << CP0C1_EP), + .CP0_Config2 = MIPS_CONFIG2, + .CP0_Config3 = MIPS_CONFIG3 | (1 << CP0C3_LPA) | (1 << CP0C3_DSPP) , + .CP0_Config4 = MIPS_CONFIG4 | (1U << CP0C4_M) | + (0x3c << CP0C4_KScrExist) | (1U << CP0C4_MMUExtDef) | + (3U << CP0C4_MMUSizeExt), + .CP0_LLAddr_rw_bitmask = 0, + .CP0_LLAddr_shift = 4, + .CP0_PageGrain = (1 << CP0PG_ELPA), + .SYNCI_Step = 32, + .CCRes = 2, + .CP0_Status_rw_bitmask = 0x12F8FFFF, + .SEGBITS = 42, + .PABITS = 49, + .insn_flags = CPU_MIPS64R2 | INSN_OCTEON | ASE_DSP, + .mmu_type = MMU_TYPE_R4000, + }, #endif };