Adds support for emulating the S32LDD and S32LDDR MXU instructions. Signed-off-by: Craig Janeczek <jancr...@amazon.com> --- v1 - initial patch v2 - changed bitfield usage to extract32
target/mips/translate.c | 43 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 38 insertions(+), 5 deletions(-) diff --git a/target/mips/translate.c b/target/mips/translate.c index e2def36b03..2eb7c02741 100644 --- a/target/mips/translate.c +++ b/target/mips/translate.c @@ -347,7 +347,8 @@ enum { OPC_MSUB = 0x04 | OPC_SPECIAL2, OPC_MSUBU = 0x05 | OPC_SPECIAL2, /* Loongson 2F */ - OPC_MULT_G_2F = 0x10 | OPC_SPECIAL2, + /* opcode 0x10 overlaps loongson and MXU command */ + OPC_MULT_G_2F_MXU_S32LDD = 0x10 | OPC_SPECIAL2, OPC_DMULT_G_2F = 0x11 | OPC_SPECIAL2, OPC_MULTU_G_2F = 0x12 | OPC_SPECIAL2, OPC_DMULTU_G_2F = 0x13 | OPC_SPECIAL2, @@ -3776,7 +3777,7 @@ static void gen_cl (DisasContext *ctx, uint32_t opc, static void gen_mxu(DisasContext *ctx, uint32_t opc) { TCGv t0, t1, t2, t3, t4, t5, t6, t7; - uint32_t rb, xra, xrb, xrc, xrd, s8, sel, optn2, optn3, aptn2; + uint32_t rb, xra, xrb, xrc, xrd, s8, s12, sel, optn2, optn3, aptn2; t0 = tcg_temp_new(); t1 = tcg_temp_new(); @@ -3858,6 +3859,29 @@ static void gen_mxu(DisasContext *ctx, uint32_t opc) gen_store_mxu_gpr(t0, xra); break; + case OPC_MULT_G_2F_MXU_S32LDD: + xra = extract32(ctx->opcode, 6, 4); + s12 = extract32(ctx->opcode, 10, 10); + sel = extract32(ctx->opcode, 20, 1); + rb = extract32(ctx->opcode, 21, 5); + + gen_load_gpr(t0, rb); + + tcg_gen_movi_tl(t1, s12); + tcg_gen_shli_tl(t1, t1, 2); + if (s12 & 0x200) { + tcg_gen_ori_tl(t1, t1, 0xFFFFF000); + } + tcg_gen_add_tl(t1, t0, t1); + tcg_gen_qemu_ld_tl(t1, t1, ctx->mem_idx, MO_SL); + + if (sel == 1) { + /* S32LDDR */ + tcg_gen_bswap32_tl(t1, t1); + } + gen_store_mxu_gpr(t1, xra); + break; + case OPC_MXU_D16MUL: xra = extract32(ctx->opcode, 6, 4); xrb = extract32(ctx->opcode, 10, 4); @@ -4039,7 +4063,7 @@ static void gen_loongson_integer(DisasContext *ctx, uint32_t opc, switch (opc) { case OPC_MULT_G_2E: - case OPC_MULT_G_2F: + case OPC_MULT_G_2F_MXU_S32LDD: case OPC_MULTU_G_2E: case OPC_MULTU_G_2F: #if defined(TARGET_MIPS64) @@ -4062,7 +4086,7 @@ static void gen_loongson_integer(DisasContext *ctx, uint32_t opc, switch (opc) { case OPC_MULT_G_2E: - case OPC_MULT_G_2F: + case OPC_MULT_G_2F_MXU_S32LDD: tcg_gen_mul_tl(cpu_gpr[rd], t0, t1); tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]); break; @@ -18099,7 +18123,6 @@ static void decode_opc_special2_legacy(CPUMIPSState *env, DisasContext *ctx) 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: @@ -18116,6 +18139,16 @@ static void decode_opc_special2_legacy(CPUMIPSState *env, DisasContext *ctx) gen_mxu(ctx, op1); break; + case OPC_MULT_G_2F_MXU_S32LDD: + /* There is an overlap of opcodes between Loongson2F and MXU */ + if (ctx->insn_flags & INSN_LOONGSON2F) { + check_insn(ctx, INSN_LOONGSON2F); + gen_loongson_integer(ctx, op1, rd, rs, rt); + } else { + gen_mxu(ctx, op1); + } + break; + case OPC_CLO: case OPC_CLZ: check_insn(ctx, ISA_MIPS32); -- 2.18.0