From fa0d2f69e716cdc67012109f1f991c32ab961082 Mon Sep 17 00:00:00 2001 From: Leon Alrae Date: Fri, 27 Jun 2014 08:49:00 +0100 Subject: [PATCH 01/28] target-mips: define ISA_MIPS64R6 Signed-off-by: Leon Alrae Reviewed-by: Aurelien Jarno --- target-mips/mips-defs.h | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/target-mips/mips-defs.h b/target-mips/mips-defs.h index 9dfa5168da..6cb62b2df0 100644 --- a/target-mips/mips-defs.h +++ b/target-mips/mips-defs.h @@ -30,17 +30,21 @@ #define ISA_MIPS64 0x00000080 #define ISA_MIPS64R2 0x00000100 #define ISA_MIPS32R3 0x00000200 -#define ISA_MIPS32R5 0x00000400 +#define ISA_MIPS64R3 0x00000400 +#define ISA_MIPS32R5 0x00000800 +#define ISA_MIPS64R5 0x00001000 +#define ISA_MIPS32R6 0x00002000 +#define ISA_MIPS64R6 0x00004000 /* MIPS ASEs. */ -#define ASE_MIPS16 0x00001000 -#define ASE_MIPS3D 0x00002000 -#define ASE_MDMX 0x00004000 -#define ASE_DSP 0x00008000 -#define ASE_DSPR2 0x00010000 -#define ASE_MT 0x00020000 -#define ASE_SMARTMIPS 0x00040000 -#define ASE_MICROMIPS 0x00080000 +#define ASE_MIPS16 0x00010000 +#define ASE_MIPS3D 0x00020000 +#define ASE_MDMX 0x00040000 +#define ASE_DSP 0x00080000 +#define ASE_DSPR2 0x00100000 +#define ASE_MT 0x00200000 +#define ASE_SMARTMIPS 0x00400000 +#define ASE_MICROMIPS 0x00800000 /* Chip specific instructions. */ #define INSN_LOONGSON2E 0x20000000 @@ -68,9 +72,15 @@ /* MIPS Technologies "Release 3" */ #define CPU_MIPS32R3 (CPU_MIPS32R2 | ISA_MIPS32R3) +#define CPU_MIPS64R3 (CPU_MIPS64R2 | CPU_MIPS32R3 | ISA_MIPS64R3) /* MIPS Technologies "Release 5" */ #define CPU_MIPS32R5 (CPU_MIPS32R3 | ISA_MIPS32R5) +#define CPU_MIPS64R5 (CPU_MIPS64R3 | CPU_MIPS32R5 | ISA_MIPS64R5) + +/* MIPS Technologies "Release 6" */ +#define CPU_MIPS32R6 (CPU_MIPS32R5 | ISA_MIPS32R6) +#define CPU_MIPS64R6 (CPU_MIPS64R5 | CPU_MIPS32R6 | ISA_MIPS64R6) /* Strictly follow the architecture standard: - Disallow "special" instruction handling for PMON/SPIM. From fecd2646957bf7c2e0612c6b218903d982560014 Mon Sep 17 00:00:00 2001 From: Leon Alrae Date: Fri, 27 Jun 2014 08:49:00 +0100 Subject: [PATCH 02/28] target-mips: signal RI Exception on instructions removed in R6 Signal Reserved Instruction Exception on instructions that do not exist in R6. In this commit the following groups of preR6 instructions are marked as deleted: - Floating Point Paired Single - Floating Point Compare - conditional moves / branches on FPU conditions - branch likelies - unaligned loads / stores - traps - legacy accumulator instructions - COP1X - MIPS-3D Signed-off-by: Leon Alrae Reviewed-by: Aurelien Jarno --- target-mips/translate.c | 64 +++++++++++++++++++++++++++++++++++------ 1 file changed, 56 insertions(+), 8 deletions(-) diff --git a/target-mips/translate.c b/target-mips/translate.c index 06db150325..de1174736d 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -1436,6 +1436,16 @@ static inline void check_insn(DisasContext *ctx, int flags) } } +/* This code generates a "reserved instruction" exception if the + CPU has corresponding flag set which indicates that the instruction + has been removed. */ +static inline void check_insn_opc_removed(DisasContext *ctx, int flags) +{ + if (unlikely(ctx->insn_flags & flags)) { + generate_exception(ctx, EXCP_RI); + } +} + /* This code generates a "reserved instruction" exception if 64-bit instructions are not enabled. */ static inline void check_mips_64(DisasContext *ctx) @@ -7712,10 +7722,12 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, opn = "floor.w.s"; break; case OPC_MOVCF_S: + check_insn_opc_removed(ctx, ISA_MIPS32R6); gen_movcf_s(fs, fd, (ft >> 2) & 0x7, ft & 0x1); opn = "movcf.s"; break; case OPC_MOVZ_S: + check_insn_opc_removed(ctx, ISA_MIPS32R6); { int l1 = gen_new_label(); TCGv_i32 fp0; @@ -7732,6 +7744,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, opn = "movz.s"; break; case OPC_MOVN_S: + check_insn_opc_removed(ctx, ISA_MIPS32R6); { int l1 = gen_new_label(); TCGv_i32 fp0; @@ -7865,6 +7878,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, opn = "cvt.l.s"; break; case OPC_CVT_PS_S: + check_insn_opc_removed(ctx, ISA_MIPS32R6); check_cp1_64bitmode(ctx); { TCGv_i64 fp64 = tcg_temp_new_i64(); @@ -7897,6 +7911,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, case OPC_CMP_NGE_S: case OPC_CMP_LE_S: case OPC_CMP_NGT_S: + check_insn_opc_removed(ctx, ISA_MIPS32R6); if (ctx->opcode & (1 << 6)) { gen_cmpabs_s(ctx, func-48, ft, fs, cc); opn = condnames_abs[func-48]; @@ -8121,10 +8136,12 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, opn = "floor.w.d"; break; case OPC_MOVCF_D: + check_insn_opc_removed(ctx, ISA_MIPS32R6); gen_movcf_d(ctx, fs, fd, (ft >> 2) & 0x7, ft & 0x1); opn = "movcf.d"; break; case OPC_MOVZ_D: + check_insn_opc_removed(ctx, ISA_MIPS32R6); { int l1 = gen_new_label(); TCGv_i64 fp0; @@ -8141,6 +8158,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, opn = "movz.d"; break; case OPC_MOVN_D: + check_insn_opc_removed(ctx, ISA_MIPS32R6); { int l1 = gen_new_label(); TCGv_i64 fp0; @@ -8250,6 +8268,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, case OPC_CMP_NGE_D: case OPC_CMP_LE_D: case OPC_CMP_NGT_D: + check_insn_opc_removed(ctx, ISA_MIPS32R6); if (ctx->opcode & (1 << 6)) { gen_cmpabs_d(ctx, func-48, ft, fs, cc); opn = condnames_abs[func-48]; @@ -8350,6 +8369,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, opn = "cvt.d.l"; break; case OPC_CVT_PS_PW: + check_insn_opc_removed(ctx, ISA_MIPS32R6); check_cp1_64bitmode(ctx); { TCGv_i64 fp0 = tcg_temp_new_i64(); @@ -14508,6 +14528,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx) break; case OPC_MOVN: /* Conditional move */ case OPC_MOVZ: + check_insn_opc_removed(ctx, ISA_MIPS32R6); check_insn(ctx, ISA_MIPS4 | ISA_MIPS32 | INSN_LOONGSON2E | INSN_LOONGSON2F); gen_cond_move(ctx, op1, rd, rs, rt); @@ -14568,10 +14589,12 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx) break; case OPC_MFHI: /* Move from HI/LO */ case OPC_MFLO: + check_insn_opc_removed(ctx, ISA_MIPS32R6); gen_HILO(ctx, op1, rs & 3, rd); break; case OPC_MTHI: case OPC_MTLO: /* Move to HI/LO */ + check_insn_opc_removed(ctx, ISA_MIPS32R6); gen_HILO(ctx, op1, rd & 3, rs); break; case OPC_PMON: /* Pmon entry point, also R4010 selsl */ @@ -14604,6 +14627,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx) break; case OPC_MOVCI: + check_insn_opc_removed(ctx, ISA_MIPS32R6); check_insn(ctx, ISA_MIPS4 | ISA_MIPS32); if (ctx->CP0_Config1 & (1 << CP0C1_FP)) { check_cp1_enabled(ctx); @@ -14706,10 +14730,12 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx) switch (op1) { case OPC_MADD ... OPC_MADDU: /* Multiply and add/sub */ case OPC_MSUB ... OPC_MSUBU: + check_insn_opc_removed(ctx, ISA_MIPS32R6); check_insn(ctx, ISA_MIPS32); gen_muldiv(ctx, op1, rd & 3, rs, rt); break; case OPC_MUL: + check_insn_opc_removed(ctx, ISA_MIPS32R6); gen_arith(ctx, op1, rd, rs, rt); break; case OPC_CLO: @@ -15327,12 +15353,20 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx) case OPC_REGIMM: op1 = MASK_REGIMM(ctx->opcode); switch (op1) { - case OPC_BLTZ ... OPC_BGEZL: /* REGIMM branches */ - case OPC_BLTZAL ... OPC_BGEZALL: + case OPC_BLTZL: /* REGIMM branches */ + case OPC_BGEZL: + case OPC_BLTZALL: + case OPC_BGEZALL: + check_insn_opc_removed(ctx, ISA_MIPS32R6); + case OPC_BLTZ: + case OPC_BGEZ: + case OPC_BLTZAL: + case OPC_BGEZAL: gen_compute_branch(ctx, op1, 4, rs, -1, imm << 2); break; case OPC_TGEI ... OPC_TEQI: /* REGIMM traps */ case OPC_TNEI: + check_insn_opc_removed(ctx, ISA_MIPS32R6); gen_trap(ctx, op1, rs, -1, imm); break; case OPC_SYNCI: @@ -15457,16 +15491,24 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx) offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 2; gen_compute_branch(ctx, op, 4, rs, rt, offset); break; - case OPC_BEQ ... OPC_BGTZ: /* Branch */ - case OPC_BEQL ... OPC_BGTZL: + case OPC_BEQL ... OPC_BGTZL: /* Branch */ + check_insn_opc_removed(ctx, ISA_MIPS32R6); + case OPC_BEQ ... OPC_BGTZ: gen_compute_branch(ctx, op, 4, rs, rt, imm << 2); break; - case OPC_LB ... OPC_LWR: /* Load and stores */ + case OPC_LWL: /* Load and stores */ + case OPC_LWR: + check_insn_opc_removed(ctx, ISA_MIPS32R6); + case OPC_LB ... OPC_LH: + case OPC_LW ... OPC_LHU: case OPC_LL: gen_ld(ctx, op, rt, rs, imm); break; - case OPC_SB ... OPC_SW: + case OPC_SWL: case OPC_SWR: + check_insn_opc_removed(ctx, ISA_MIPS32R6); + case OPC_SB ... OPC_SH: + case OPC_SW: gen_st(ctx, op, rt, rs, imm); break; case OPC_SC: @@ -15513,18 +15555,21 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx) #endif case OPC_BC1ANY2: case OPC_BC1ANY4: + check_insn_opc_removed(ctx, ISA_MIPS32R6); check_cop1x(ctx); check_insn(ctx, ASE_MIPS3D); /* fall through */ case OPC_BC1: + check_insn_opc_removed(ctx, ISA_MIPS32R6); gen_compute_branch1(ctx, MASK_BC1(ctx->opcode), (rt >> 2) & 0x7, imm << 2); break; + case OPC_PS_FMT: + check_insn_opc_removed(ctx, ISA_MIPS32R6); case OPC_S_FMT: case OPC_D_FMT: case OPC_W_FMT: case OPC_L_FMT: - case OPC_PS_FMT: gen_farith(ctx, ctx->opcode & FOP(0x3f, 0x1f), rt, rd, sa, (imm >> 8) & 0x7); break; @@ -15553,6 +15598,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx) break; case OPC_CP3: + check_insn_opc_removed(ctx, ISA_MIPS32R6); if (ctx->CP0_Config1 & (1 << CP0C1_FP)) { check_cp1_enabled(ctx); op1 = MASK_CP3(ctx->opcode); @@ -15595,8 +15641,9 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx) #if defined(TARGET_MIPS64) /* MIPS64 opcodes */ - case OPC_LWU: case OPC_LDL ... OPC_LDR: + check_insn_opc_removed(ctx, ISA_MIPS32R6); + case OPC_LWU: case OPC_LLD: case OPC_LD: check_insn(ctx, ISA_MIPS3); @@ -15604,6 +15651,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx) gen_ld(ctx, op, rt, rs, imm); break; case OPC_SDL ... OPC_SDR: + check_insn_opc_removed(ctx, ISA_MIPS32R6); case OPC_SD: check_insn(ctx, ISA_MIPS3); check_mips_64(ctx); From b691d9d2a0c13ad27df44964f6fdd34d5f259607 Mon Sep 17 00:00:00 2001 From: Leon Alrae Date: Fri, 27 Jun 2014 08:49:01 +0100 Subject: [PATCH 03/28] target-mips: add SELEQZ and SELNEZ instructions Signed-off-by: Leon Alrae Reviewed-by: Aurelien Jarno Reviewed-by: James Hogan --- disas/mips.c | 8 ++++++++ target-mips/translate.c | 18 ++++++++++++++++-- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/disas/mips.c b/disas/mips.c index 2106b574cb..b950e539e8 100644 --- a/disas/mips.c +++ b/disas/mips.c @@ -521,6 +521,8 @@ struct mips_opcode #define INSN_ISA64 0x00000040 #define INSN_ISA32R2 0x00000080 #define INSN_ISA64R2 0x00000100 +#define INSN_ISA32R6 0x00000200 +#define INSN_ISA64R6 0x00000400 /* Masks used for MIPS-defined ASEs. */ #define INSN_ASE_MASK 0x0000f000 @@ -585,6 +587,8 @@ struct mips_opcode #define ISA_MIPS32R2 (ISA_MIPS32 | INSN_ISA32R2) #define ISA_MIPS64R2 (ISA_MIPS64 | INSN_ISA32R2 | INSN_ISA64R2) +#define ISA_MIPS32R6 (ISA_MIPS32R2 | INSN_ISA32R6) +#define ISA_MIPS64R6 (ISA_MIPS64R2 | INSN_ISA32R6 | INSN_ISA64R6) /* CPU defines, use instead of hardcoding processor number. Keep this in sync with bfd/archures.c in order for machine selection to work. */ @@ -1121,6 +1125,8 @@ extern const int bfd_mips16_num_opcodes; #define I64 INSN_ISA64 #define I33 INSN_ISA32R2 #define I65 INSN_ISA64R2 +#define I32R6 INSN_ISA32R6 +#define I64R6 INSN_ISA64R6 /* MIPS64 MIPS-3D ASE support. */ #define I16 INSN_MIPS16 @@ -1209,6 +1215,8 @@ const struct mips_opcode mips_builtin_opcodes[] = them first. The assemblers uses a hash table based on the instruction name anyhow. */ /* name, args, match, mask, pinfo, membership */ +{"seleqz", "d,v,t", 0x00000035, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I32R6}, +{"selnez", "d,v,t", 0x00000037, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I32R6}, {"pref", "k,o(b)", 0xcc000000, 0xfc000000, RD_b, 0, I4|I32|G3 }, {"prefx", "h,t(b)", 0x4c00000f, 0xfc0007ff, RD_b|RD_t, 0, I4|I33 }, {"nop", "", 0x00000000, 0xffffffff, 0, INSN2_ALIAS, I1 }, /* sll */ diff --git a/target-mips/translate.c b/target-mips/translate.c index de1174736d..ba9daac32b 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -193,6 +193,9 @@ enum { OPC_MOVZ = 0x0A | OPC_SPECIAL, OPC_MOVN = 0x0B | OPC_SPECIAL, + OPC_SELEQZ = 0x35 | OPC_SPECIAL, + OPC_SELNEZ = 0x37 | OPC_SPECIAL, + OPC_MOVCI = 0x01 | OPC_SPECIAL, /* Special */ @@ -205,8 +208,6 @@ enum { OPC_SPECIAL15_RESERVED = 0x15 | OPC_SPECIAL, OPC_SPECIAL28_RESERVED = 0x28 | OPC_SPECIAL, OPC_SPECIAL29_RESERVED = 0x29 | OPC_SPECIAL, - OPC_SPECIAL35_RESERVED = 0x35 | OPC_SPECIAL, - OPC_SPECIAL37_RESERVED = 0x37 | OPC_SPECIAL, OPC_SPECIAL39_RESERVED = 0x39 | OPC_SPECIAL, OPC_SPECIAL3D_RESERVED = 0x3D | OPC_SPECIAL, }; @@ -2412,6 +2413,14 @@ static void gen_cond_move(DisasContext *ctx, uint32_t opc, tcg_gen_movcond_tl(TCG_COND_EQ, cpu_gpr[rd], t0, t1, t2, cpu_gpr[rd]); opn = "movz"; break; + case OPC_SELNEZ: + tcg_gen_movcond_tl(TCG_COND_NE, cpu_gpr[rd], t0, t1, t2, t1); + opn = "selnez"; + break; + case OPC_SELEQZ: + tcg_gen_movcond_tl(TCG_COND_EQ, cpu_gpr[rd], t0, t1, t2, t1); + opn = "seleqz"; + break; } tcg_temp_free(t2); tcg_temp_free(t1); @@ -14533,6 +14542,11 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx) INSN_LOONGSON2E | INSN_LOONGSON2F); gen_cond_move(ctx, op1, rd, rs, rt); break; + case OPC_SELEQZ: + case OPC_SELNEZ: + check_insn(ctx, ISA_MIPS32R6); + gen_cond_move(ctx, op1, rd, rs, rt); + break; case OPC_ADD ... OPC_SUBU: gen_arith(ctx, op1, rd, rs, rt); break; From 4368b29a26ebd13db95325b3511c0157ea9826f0 Mon Sep 17 00:00:00 2001 From: Leon Alrae Date: Fri, 27 Jun 2014 08:49:01 +0100 Subject: [PATCH 04/28] target-mips: move LL and SC instructions The encoding of LL and SC instruction has changed in MIPS32 Release 6. Signed-off-by: Leon Alrae Reviewed-by: Aurelien Jarno Reviewed-by: James Hogan --- disas/mips.c | 9 ++++++++- target-mips/translate.c | 28 ++++++++++++++++++++++++++-- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/disas/mips.c b/disas/mips.c index b950e539e8..f0efa8b29c 100644 --- a/disas/mips.c +++ b/disas/mips.c @@ -119,6 +119,8 @@ see . */ #define OP_SH_IMMEDIATE 0 #define OP_MASK_DELTA 0xffff #define OP_SH_DELTA 0 +#define OP_MASK_DELTA_R6 0x1ff +#define OP_SH_DELTA_R6 7 #define OP_MASK_FUNCT 0x3f #define OP_SH_FUNCT 0 #define OP_MASK_SPEC 0x3f @@ -1215,6 +1217,8 @@ const struct mips_opcode mips_builtin_opcodes[] = them first. The assemblers uses a hash table based on the instruction name anyhow. */ /* name, args, match, mask, pinfo, membership */ +{"ll", "t,o(b)", 0x7c000036, 0xfc00007f, LDD|RD_b|WR_t, 0, I32R6}, +{"sc", "t,o(b)", 0x7c000026, 0xfc00007f, LDD|RD_b|WR_t, 0, I32R6}, {"seleqz", "d,v,t", 0x00000035, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I32R6}, {"selnez", "d,v,t", 0x00000037, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I32R6}, {"pref", "k,o(b)", 0xcc000000, 0xfc000000, RD_b, 0, I4|I32|G3 }, @@ -3734,7 +3738,10 @@ print_insn_args (const char *d, case 'j': /* Same as i, but sign-extended. */ case 'o': - delta = (l >> OP_SH_DELTA) & OP_MASK_DELTA; + delta = (opp->membership == I32R6) ? + (l >> OP_SH_DELTA_R6) & OP_MASK_DELTA_R6 : + (l >> OP_SH_DELTA) & OP_MASK_DELTA; + if (delta & 0x8000) delta |= ~0xffff; (*info->fprintf_func) (info->stream, "%d", diff --git a/target-mips/translate.c b/target-mips/translate.c index ba9daac32b..8606f32499 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -347,6 +347,10 @@ enum { /* MIPS DSP Accumulator and DSPControl Access Sub-class */ OPC_EXTR_W_DSP = 0x38 | OPC_SPECIAL3, OPC_DEXTR_W_DSP = 0x3C | OPC_SPECIAL3, + + /* R6 */ + R6_OPC_LL = 0x36 | OPC_SPECIAL3, + R6_OPC_SC = 0x26 | OPC_SPECIAL3, }; /* BSHFL opcodes */ @@ -1775,6 +1779,7 @@ static void gen_ld(DisasContext *ctx, uint32_t opc, opn = "lwr"; break; case OPC_LL: + case R6_OPC_LL: save_cpu_state(ctx, 1); op_ld_ll(t0, t0, ctx); gen_store_gpr(t0, rt); @@ -1868,6 +1873,7 @@ static void gen_st_cond (DisasContext *ctx, uint32_t opc, int rt, break; #endif case OPC_SC: + case R6_OPC_SC: save_cpu_state(ctx, 1); op_st_sc(t1, t0, rt, ctx); opn = "sc"; @@ -14804,6 +14810,10 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx) case OPC_SPECIAL3: op1 = MASK_SPECIAL3(ctx->opcode); switch (op1) { + case R6_OPC_LL: + check_insn(ctx, ISA_MIPS32R6); + gen_ld(ctx, op1, rt, rs, imm >> 7); + break; case OPC_EXT: case OPC_INS: check_insn(ctx, ISA_MIPS32R2); @@ -15108,6 +15118,19 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx) break; } break; + case R6_OPC_SC: /* OPC_DMOD_G_2E */ + if (ctx->insn_flags & ISA_MIPS32R6) { + gen_st_cond(ctx, op1, rt, rs, imm >> 7); + } else { +#if defined(TARGET_MIPS64) + check_insn(ctx, INSN_LOONGSON2E); + gen_loongson_integer(ctx, op1, rd, rs, rt); +#else + /* Invalid in MIPS32 */ + generate_exception(ctx, EXCP_RI); +#endif + } + break; #if defined(TARGET_MIPS64) case OPC_DEXTM ... OPC_DEXT: case OPC_DINSM ... OPC_DINS: @@ -15123,7 +15146,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx) break; case OPC_DDIV_G_2E ... OPC_DDIVU_G_2E: case OPC_DMULT_G_2E ... OPC_DMULTU_G_2E: - case OPC_DMOD_G_2E ... OPC_DMODU_G_2E: + case OPC_DMODU_G_2E: check_insn(ctx, INSN_LOONGSON2E); gen_loongson_integer(ctx, op1, rd, rs, rt); break; @@ -15512,10 +15535,10 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx) break; case OPC_LWL: /* Load and stores */ case OPC_LWR: + case OPC_LL: check_insn_opc_removed(ctx, ISA_MIPS32R6); case OPC_LB ... OPC_LH: case OPC_LW ... OPC_LHU: - case OPC_LL: gen_ld(ctx, op, rt, rs, imm); break; case OPC_SWL: @@ -15526,6 +15549,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx) gen_st(ctx, op, rt, rs, imm); break; case OPC_SC: + check_insn_opc_removed(ctx, ISA_MIPS32R6); gen_st_cond(ctx, op, rt, rs, imm); break; case OPC_CACHE: From 099e5b4d9fe99860b5533d09fac7ac8b64c12b53 Mon Sep 17 00:00:00 2001 From: Leon Alrae Date: Fri, 27 Jun 2014 08:49:01 +0100 Subject: [PATCH 05/28] target-mips: extract decode_opc_special* from decode_opc Creating separate decode functions for special, special2 and special3 instructions to ease adding new R6 instructions and removing legacy instructions. Signed-off-by: Leon Alrae Reviewed-by: Aurelien Jarno --- target-mips/translate.c | 1768 ++++++++++++++++++++------------------- 1 file changed, 904 insertions(+), 864 deletions(-) diff --git a/target-mips/translate.c b/target-mips/translate.c index 8606f32499..5b8f762ec6 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -14482,11 +14482,910 @@ static void gen_mipsdsp_accinsn(DisasContext *ctx, uint32_t op1, uint32_t op2, /* End MIPSDSP functions. */ +static void decode_opc_special(CPUMIPSState *env, DisasContext *ctx) +{ + int rs, rt, rd, sa; + uint32_t op1; + + rs = (ctx->opcode >> 21) & 0x1f; + rt = (ctx->opcode >> 16) & 0x1f; + rd = (ctx->opcode >> 11) & 0x1f; + sa = (ctx->opcode >> 6) & 0x1f; + + op1 = MASK_SPECIAL(ctx->opcode); + switch (op1) { + case OPC_SLL: /* Shift with immediate */ + case OPC_SRA: + gen_shift_imm(ctx, op1, rd, rt, sa); + break; + case OPC_SRL: + switch ((ctx->opcode >> 21) & 0x1f) { + case 1: + /* rotr is decoded as srl on non-R2 CPUs */ + if (ctx->insn_flags & ISA_MIPS32R2) { + op1 = OPC_ROTR; + } + /* Fallthrough */ + case 0: + gen_shift_imm(ctx, op1, rd, rt, sa); + break; + default: + generate_exception(ctx, EXCP_RI); + break; + } + break; + case OPC_MOVN: /* Conditional move */ + case OPC_MOVZ: + check_insn_opc_removed(ctx, ISA_MIPS32R6); + check_insn(ctx, ISA_MIPS4 | ISA_MIPS32 | + INSN_LOONGSON2E | INSN_LOONGSON2F); + gen_cond_move(ctx, op1, rd, rs, rt); + break; + case OPC_SELEQZ: + case OPC_SELNEZ: + check_insn(ctx, ISA_MIPS32R6); + gen_cond_move(ctx, op1, rd, rs, rt); + break; + case OPC_ADD ... OPC_SUBU: + gen_arith(ctx, op1, rd, rs, rt); + break; + case OPC_SLLV: /* Shifts */ + case OPC_SRAV: + gen_shift(ctx, op1, rd, rs, rt); + break; + case OPC_SRLV: + switch ((ctx->opcode >> 6) & 0x1f) { + case 1: + /* rotrv is decoded as srlv on non-R2 CPUs */ + if (ctx->insn_flags & ISA_MIPS32R2) { + op1 = OPC_ROTRV; + } + /* Fallthrough */ + case 0: + gen_shift(ctx, op1, rd, rs, rt); + break; + default: + generate_exception(ctx, EXCP_RI); + break; + } + break; + case OPC_SLT: /* Set on less than */ + case OPC_SLTU: + gen_slt(ctx, op1, rd, rs, rt); + break; + case OPC_AND: /* Logic*/ + case OPC_OR: + case OPC_NOR: + case OPC_XOR: + gen_logic(ctx, op1, rd, rs, rt); + break; + case OPC_MULT: + case OPC_MULTU: + if (sa) { + check_insn(ctx, INSN_VR54XX); + op1 = MASK_MUL_VR54XX(ctx->opcode); + gen_mul_vr54xx(ctx, op1, rd, rs, rt); + } else { + gen_muldiv(ctx, op1, rd & 3, rs, rt); + } + break; + case OPC_DIV: + case OPC_DIVU: + gen_muldiv(ctx, op1, 0, rs, rt); + break; + case OPC_JR ... OPC_JALR: + gen_compute_branch(ctx, op1, 4, rs, rd, sa); + break; + case OPC_TGE ... OPC_TEQ: /* Traps */ + case OPC_TNE: + gen_trap(ctx, op1, rs, rt, -1); + break; + case OPC_MFHI: /* Move from HI/LO */ + case OPC_MFLO: + check_insn_opc_removed(ctx, ISA_MIPS32R6); + gen_HILO(ctx, op1, rs & 3, rd); + break; + case OPC_MTHI: + case OPC_MTLO: /* Move to HI/LO */ + check_insn_opc_removed(ctx, ISA_MIPS32R6); + gen_HILO(ctx, op1, rd & 3, rs); + break; + case OPC_PMON: /* Pmon entry point, also R4010 selsl */ +#ifdef MIPS_STRICT_STANDARD + MIPS_INVAL("PMON / selsl"); + generate_exception(ctx, EXCP_RI); +#else + gen_helper_0e0i(pmon, sa); +#endif + break; + case OPC_SYSCALL: + generate_exception(ctx, EXCP_SYSCALL); + ctx->bstate = BS_STOP; + break; + case OPC_BREAK: + generate_exception(ctx, EXCP_BREAK); + break; + case OPC_SPIM: +#ifdef MIPS_STRICT_STANDARD + MIPS_INVAL("SPIM"); + generate_exception(ctx, EXCP_RI); +#else + /* Implemented as RI exception for now. */ + MIPS_INVAL("spim (unofficial)"); + generate_exception(ctx, EXCP_RI); +#endif + break; + case OPC_SYNC: + /* Treat as NOP. */ + break; + + case OPC_MOVCI: + check_insn_opc_removed(ctx, ISA_MIPS32R6); + check_insn(ctx, ISA_MIPS4 | ISA_MIPS32); + if (ctx->CP0_Config1 & (1 << CP0C1_FP)) { + check_cp1_enabled(ctx); + gen_movci(ctx, rd, rs, (ctx->opcode >> 18) & 0x7, + (ctx->opcode >> 16) & 1); + } else { + generate_exception_err(ctx, EXCP_CpU, 1); + } + break; + +#if defined(TARGET_MIPS64) + /* MIPS64 specific opcodes */ + case OPC_DSLL: + case OPC_DSRA: + case OPC_DSLL32: + case OPC_DSRA32: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); + gen_shift_imm(ctx, op1, rd, rt, sa); + break; + case OPC_DSRL: + switch ((ctx->opcode >> 21) & 0x1f) { + case 1: + /* drotr is decoded as dsrl on non-R2 CPUs */ + if (ctx->insn_flags & ISA_MIPS32R2) { + op1 = OPC_DROTR; + } + /* Fallthrough */ + case 0: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); + gen_shift_imm(ctx, op1, rd, rt, sa); + break; + default: + generate_exception(ctx, EXCP_RI); + break; + } + break; + case OPC_DSRL32: + switch ((ctx->opcode >> 21) & 0x1f) { + case 1: + /* drotr32 is decoded as dsrl32 on non-R2 CPUs */ + if (ctx->insn_flags & ISA_MIPS32R2) { + op1 = OPC_DROTR32; + } + /* Fallthrough */ + case 0: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); + gen_shift_imm(ctx, op1, rd, rt, sa); + break; + default: + generate_exception(ctx, EXCP_RI); + break; + } + break; + case OPC_DADD ... OPC_DSUBU: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); + gen_arith(ctx, op1, rd, rs, rt); + break; + case OPC_DSLLV: + case OPC_DSRAV: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); + gen_shift(ctx, op1, rd, rs, rt); + break; + case OPC_DSRLV: + switch ((ctx->opcode >> 6) & 0x1f) { + case 1: + /* drotrv is decoded as dsrlv on non-R2 CPUs */ + if (ctx->insn_flags & ISA_MIPS32R2) { + op1 = OPC_DROTRV; + } + /* Fallthrough */ + case 0: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); + gen_shift(ctx, op1, rd, rs, rt); + break; + default: + generate_exception(ctx, EXCP_RI); + break; + } + break; + case OPC_DMULT ... OPC_DDIVU: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); + gen_muldiv(ctx, op1, 0, rs, rt); + break; +#endif + default: /* Invalid */ + MIPS_INVAL("special"); + generate_exception(ctx, EXCP_RI); + break; + } +} + +static void decode_opc_special2(CPUMIPSState *env, DisasContext *ctx) +{ + int rs, rt, rd; + uint32_t op1; + + rs = (ctx->opcode >> 21) & 0x1f; + rt = (ctx->opcode >> 16) & 0x1f; + rd = (ctx->opcode >> 11) & 0x1f; + + op1 = MASK_SPECIAL2(ctx->opcode); + switch (op1) { + case OPC_MADD ... OPC_MADDU: /* Multiply and add/sub */ + case OPC_MSUB ... OPC_MSUBU: + check_insn_opc_removed(ctx, ISA_MIPS32R6); + check_insn(ctx, ISA_MIPS32); + gen_muldiv(ctx, op1, rd & 3, rs, rt); + break; + case OPC_MUL: + check_insn_opc_removed(ctx, ISA_MIPS32R6); + gen_arith(ctx, op1, rd, rs, rt); + break; + case OPC_CLO: + case OPC_CLZ: + check_insn(ctx, ISA_MIPS32); + gen_cl(ctx, op1, rd, rs); + break; + case OPC_SDBBP: + /* XXX: not clear which exception should be raised + * when in debug mode... + */ + check_insn(ctx, ISA_MIPS32); + if (!(ctx->hflags & MIPS_HFLAG_DM)) { + generate_exception(ctx, EXCP_DBp); + } else { + generate_exception(ctx, EXCP_DBp); + } + /* Treat as NOP. */ + 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(ctx, INSN_LOONGSON2F); + gen_loongson_integer(ctx, op1, rd, rs, rt); + break; +#if defined(TARGET_MIPS64) + case OPC_DCLO: + case OPC_DCLZ: + check_insn(ctx, ISA_MIPS64); + 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: + case OPC_DMOD_G_2F: + case OPC_DMODU_G_2F: + check_insn(ctx, INSN_LOONGSON2F); + gen_loongson_integer(ctx, op1, rd, rs, rt); + break; +#endif + default: /* Invalid */ + MIPS_INVAL("special2"); + generate_exception(ctx, EXCP_RI); + break; + } +} +static void decode_opc_special3(CPUMIPSState *env, DisasContext *ctx) +{ + int rs, rt, rd, sa; + uint32_t op1, op2; + int16_t imm; + + rs = (ctx->opcode >> 21) & 0x1f; + rt = (ctx->opcode >> 16) & 0x1f; + rd = (ctx->opcode >> 11) & 0x1f; + sa = (ctx->opcode >> 6) & 0x1f; + imm = (int16_t)ctx->opcode; + + op1 = MASK_SPECIAL3(ctx->opcode); + switch (op1) { + case R6_OPC_LL: + check_insn(ctx, ISA_MIPS32R6); + gen_ld(ctx, op1, rt, rs, imm >> 7); + break; + case OPC_EXT: + case OPC_INS: + check_insn(ctx, ISA_MIPS32R2); + gen_bitops(ctx, op1, rt, rs, sa, rd); + break; + case OPC_BSHFL: + check_insn(ctx, ISA_MIPS32R2); + op2 = MASK_BSHFL(ctx->opcode); + gen_bshfl(ctx, op2, rt, rd); + break; + case OPC_RDHWR: + gen_rdhwr(ctx, rt, rd); + break; + case OPC_FORK: + check_insn(ctx, ASE_MT); + { + TCGv t0 = tcg_temp_new(); + TCGv t1 = tcg_temp_new(); + + gen_load_gpr(t0, rt); + gen_load_gpr(t1, rs); + gen_helper_fork(t0, t1); + tcg_temp_free(t0); + tcg_temp_free(t1); + } + break; + case OPC_YIELD: + check_insn(ctx, ASE_MT); + { + TCGv t0 = tcg_temp_new(); + + save_cpu_state(ctx, 1); + gen_load_gpr(t0, rs); + gen_helper_yield(t0, cpu_env, t0); + gen_store_gpr(t0, rd); + tcg_temp_free(t0); + } + break; + case OPC_DIV_G_2E ... OPC_DIVU_G_2E: + case OPC_MOD_G_2E ... OPC_MODU_G_2E: + case OPC_MULT_G_2E ... OPC_MULTU_G_2E: + /* OPC_MULT_G_2E, OPC_ADDUH_QB_DSP, OPC_MUL_PH_DSP have + * the same mask and op1. */ + if ((ctx->insn_flags & ASE_DSPR2) && (op1 == OPC_MULT_G_2E)) { + op2 = MASK_ADDUH_QB(ctx->opcode); + switch (op2) { + case OPC_ADDUH_QB: + case OPC_ADDUH_R_QB: + case OPC_ADDQH_PH: + case OPC_ADDQH_R_PH: + case OPC_ADDQH_W: + case OPC_ADDQH_R_W: + case OPC_SUBUH_QB: + case OPC_SUBUH_R_QB: + case OPC_SUBQH_PH: + case OPC_SUBQH_R_PH: + case OPC_SUBQH_W: + case OPC_SUBQH_R_W: + gen_mipsdsp_arith(ctx, op1, op2, rd, rs, rt); + break; + case OPC_MUL_PH: + case OPC_MUL_S_PH: + case OPC_MULQ_S_W: + case OPC_MULQ_RS_W: + gen_mipsdsp_multiply(ctx, op1, op2, rd, rs, rt, 1); + break; + default: + MIPS_INVAL("MASK ADDUH.QB"); + generate_exception(ctx, EXCP_RI); + break; + } + } else if (ctx->insn_flags & INSN_LOONGSON2E) { + gen_loongson_integer(ctx, op1, rd, rs, rt); + } else { + generate_exception(ctx, EXCP_RI); + } + break; + case OPC_LX_DSP: + op2 = MASK_LX(ctx->opcode); + switch (op2) { +#if defined(TARGET_MIPS64) + case OPC_LDX: +#endif + case OPC_LBUX: + case OPC_LHX: + case OPC_LWX: + gen_mipsdsp_ld(ctx, op2, rd, rs, rt); + break; + default: /* Invalid */ + MIPS_INVAL("MASK LX"); + generate_exception(ctx, EXCP_RI); + break; + } + break; + case OPC_ABSQ_S_PH_DSP: + op2 = MASK_ABSQ_S_PH(ctx->opcode); + switch (op2) { + case OPC_ABSQ_S_QB: + case OPC_ABSQ_S_PH: + case OPC_ABSQ_S_W: + case OPC_PRECEQ_W_PHL: + case OPC_PRECEQ_W_PHR: + case OPC_PRECEQU_PH_QBL: + case OPC_PRECEQU_PH_QBR: + case OPC_PRECEQU_PH_QBLA: + case OPC_PRECEQU_PH_QBRA: + case OPC_PRECEU_PH_QBL: + case OPC_PRECEU_PH_QBR: + case OPC_PRECEU_PH_QBLA: + case OPC_PRECEU_PH_QBRA: + gen_mipsdsp_arith(ctx, op1, op2, rd, rs, rt); + break; + case OPC_BITREV: + case OPC_REPL_QB: + case OPC_REPLV_QB: + case OPC_REPL_PH: + case OPC_REPLV_PH: + gen_mipsdsp_bitinsn(ctx, op1, op2, rd, rt); + break; + default: + MIPS_INVAL("MASK ABSQ_S.PH"); + generate_exception(ctx, EXCP_RI); + break; + } + break; + case OPC_ADDU_QB_DSP: + op2 = MASK_ADDU_QB(ctx->opcode); + switch (op2) { + case OPC_ADDQ_PH: + case OPC_ADDQ_S_PH: + case OPC_ADDQ_S_W: + case OPC_ADDU_QB: + case OPC_ADDU_S_QB: + case OPC_ADDU_PH: + case OPC_ADDU_S_PH: + case OPC_SUBQ_PH: + case OPC_SUBQ_S_PH: + case OPC_SUBQ_S_W: + case OPC_SUBU_QB: + case OPC_SUBU_S_QB: + case OPC_SUBU_PH: + case OPC_SUBU_S_PH: + case OPC_ADDSC: + case OPC_ADDWC: + case OPC_MODSUB: + case OPC_RADDU_W_QB: + gen_mipsdsp_arith(ctx, op1, op2, rd, rs, rt); + break; + case OPC_MULEU_S_PH_QBL: + case OPC_MULEU_S_PH_QBR: + case OPC_MULQ_RS_PH: + case OPC_MULEQ_S_W_PHL: + case OPC_MULEQ_S_W_PHR: + case OPC_MULQ_S_PH: + gen_mipsdsp_multiply(ctx, op1, op2, rd, rs, rt, 1); + break; + default: /* Invalid */ + MIPS_INVAL("MASK ADDU.QB"); + generate_exception(ctx, EXCP_RI); + break; + + } + break; + case OPC_CMPU_EQ_QB_DSP: + op2 = MASK_CMPU_EQ_QB(ctx->opcode); + switch (op2) { + case OPC_PRECR_SRA_PH_W: + case OPC_PRECR_SRA_R_PH_W: + gen_mipsdsp_arith(ctx, op1, op2, rt, rs, rd); + break; + case OPC_PRECR_QB_PH: + case OPC_PRECRQ_QB_PH: + case OPC_PRECRQ_PH_W: + case OPC_PRECRQ_RS_PH_W: + case OPC_PRECRQU_S_QB_PH: + gen_mipsdsp_arith(ctx, op1, op2, rd, rs, rt); + break; + case OPC_CMPU_EQ_QB: + case OPC_CMPU_LT_QB: + case OPC_CMPU_LE_QB: + case OPC_CMP_EQ_PH: + case OPC_CMP_LT_PH: + case OPC_CMP_LE_PH: + gen_mipsdsp_add_cmp_pick(ctx, op1, op2, rd, rs, rt, 0); + break; + case OPC_CMPGU_EQ_QB: + case OPC_CMPGU_LT_QB: + case OPC_CMPGU_LE_QB: + case OPC_CMPGDU_EQ_QB: + case OPC_CMPGDU_LT_QB: + case OPC_CMPGDU_LE_QB: + case OPC_PICK_QB: + case OPC_PICK_PH: + case OPC_PACKRL_PH: + gen_mipsdsp_add_cmp_pick(ctx, op1, op2, rd, rs, rt, 1); + break; + default: /* Invalid */ + MIPS_INVAL("MASK CMPU.EQ.QB"); + generate_exception(ctx, EXCP_RI); + break; + } + break; + case OPC_SHLL_QB_DSP: + gen_mipsdsp_shift(ctx, op1, rd, rs, rt); + break; + case OPC_DPA_W_PH_DSP: + op2 = MASK_DPA_W_PH(ctx->opcode); + switch (op2) { + case OPC_DPAU_H_QBL: + case OPC_DPAU_H_QBR: + case OPC_DPSU_H_QBL: + case OPC_DPSU_H_QBR: + case OPC_DPA_W_PH: + case OPC_DPAX_W_PH: + case OPC_DPAQ_S_W_PH: + case OPC_DPAQX_S_W_PH: + case OPC_DPAQX_SA_W_PH: + case OPC_DPS_W_PH: + case OPC_DPSX_W_PH: + case OPC_DPSQ_S_W_PH: + case OPC_DPSQX_S_W_PH: + case OPC_DPSQX_SA_W_PH: + case OPC_MULSAQ_S_W_PH: + case OPC_DPAQ_SA_L_W: + case OPC_DPSQ_SA_L_W: + case OPC_MAQ_S_W_PHL: + case OPC_MAQ_S_W_PHR: + case OPC_MAQ_SA_W_PHL: + case OPC_MAQ_SA_W_PHR: + case OPC_MULSA_W_PH: + gen_mipsdsp_multiply(ctx, op1, op2, rd, rs, rt, 0); + break; + default: /* Invalid */ + MIPS_INVAL("MASK DPAW.PH"); + generate_exception(ctx, EXCP_RI); + break; + } + break; + case OPC_INSV_DSP: + op2 = MASK_INSV(ctx->opcode); + switch (op2) { + case OPC_INSV: + check_dsp(ctx); + { + TCGv t0, t1; + + if (rt == 0) { + MIPS_DEBUG("NOP"); + break; + } + + t0 = tcg_temp_new(); + t1 = tcg_temp_new(); + + gen_load_gpr(t0, rt); + gen_load_gpr(t1, rs); + + gen_helper_insv(cpu_gpr[rt], cpu_env, t1, t0); + + tcg_temp_free(t0); + tcg_temp_free(t1); + break; + } + default: /* Invalid */ + MIPS_INVAL("MASK INSV"); + generate_exception(ctx, EXCP_RI); + break; + } + break; + case OPC_APPEND_DSP: + gen_mipsdsp_append(env, ctx, op1, rt, rs, rd); + break; + case OPC_EXTR_W_DSP: + op2 = MASK_EXTR_W(ctx->opcode); + switch (op2) { + case OPC_EXTR_W: + case OPC_EXTR_R_W: + case OPC_EXTR_RS_W: + case OPC_EXTR_S_H: + case OPC_EXTRV_S_H: + case OPC_EXTRV_W: + case OPC_EXTRV_R_W: + case OPC_EXTRV_RS_W: + case OPC_EXTP: + case OPC_EXTPV: + case OPC_EXTPDP: + case OPC_EXTPDPV: + gen_mipsdsp_accinsn(ctx, op1, op2, rt, rs, rd, 1); + break; + case OPC_RDDSP: + gen_mipsdsp_accinsn(ctx, op1, op2, rd, rs, rt, 1); + break; + case OPC_SHILO: + case OPC_SHILOV: + case OPC_MTHLIP: + case OPC_WRDSP: + gen_mipsdsp_accinsn(ctx, op1, op2, rd, rs, rt, 0); + break; + default: /* Invalid */ + MIPS_INVAL("MASK EXTR.W"); + generate_exception(ctx, EXCP_RI); + break; + } + break; + case R6_OPC_SC: /* OPC_DMOD_G_2E */ + if (ctx->insn_flags & ISA_MIPS32R6) { + gen_st_cond(ctx, op1, rt, rs, imm >> 7); + } else { +#if defined(TARGET_MIPS64) + check_insn(ctx, INSN_LOONGSON2E); + gen_loongson_integer(ctx, op1, rd, rs, rt); +#else + /* Invalid in MIPS32 */ + generate_exception(ctx, EXCP_RI); +#endif + } + break; +#if defined(TARGET_MIPS64) + case OPC_DEXTM ... OPC_DEXT: + case OPC_DINSM ... OPC_DINS: + check_insn(ctx, ISA_MIPS64R2); + check_mips_64(ctx); + gen_bitops(ctx, op1, rt, rs, sa, rd); + break; + case OPC_DBSHFL: + check_insn(ctx, ISA_MIPS64R2); + check_mips_64(ctx); + op2 = MASK_DBSHFL(ctx->opcode); + gen_bshfl(ctx, op2, rt, rd); + break; + case OPC_DDIV_G_2E ... OPC_DDIVU_G_2E: + case OPC_DMULT_G_2E ... OPC_DMULTU_G_2E: + case OPC_DMODU_G_2E: + check_insn(ctx, INSN_LOONGSON2E); + gen_loongson_integer(ctx, op1, rd, rs, rt); + break; + case OPC_ABSQ_S_QH_DSP: + op2 = MASK_ABSQ_S_QH(ctx->opcode); + switch (op2) { + case OPC_PRECEQ_L_PWL: + case OPC_PRECEQ_L_PWR: + case OPC_PRECEQ_PW_QHL: + case OPC_PRECEQ_PW_QHR: + case OPC_PRECEQ_PW_QHLA: + case OPC_PRECEQ_PW_QHRA: + case OPC_PRECEQU_QH_OBL: + case OPC_PRECEQU_QH_OBR: + case OPC_PRECEQU_QH_OBLA: + case OPC_PRECEQU_QH_OBRA: + case OPC_PRECEU_QH_OBL: + case OPC_PRECEU_QH_OBR: + case OPC_PRECEU_QH_OBLA: + case OPC_PRECEU_QH_OBRA: + case OPC_ABSQ_S_OB: + case OPC_ABSQ_S_PW: + case OPC_ABSQ_S_QH: + gen_mipsdsp_arith(ctx, op1, op2, rd, rs, rt); + break; + case OPC_REPL_OB: + case OPC_REPL_PW: + case OPC_REPL_QH: + case OPC_REPLV_OB: + case OPC_REPLV_PW: + case OPC_REPLV_QH: + gen_mipsdsp_bitinsn(ctx, op1, op2, rd, rt); + break; + default: /* Invalid */ + MIPS_INVAL("MASK ABSQ_S.QH"); + generate_exception(ctx, EXCP_RI); + break; + } + break; + case OPC_ADDU_OB_DSP: + op2 = MASK_ADDU_OB(ctx->opcode); + switch (op2) { + case OPC_RADDU_L_OB: + case OPC_SUBQ_PW: + case OPC_SUBQ_S_PW: + case OPC_SUBQ_QH: + case OPC_SUBQ_S_QH: + case OPC_SUBU_OB: + case OPC_SUBU_S_OB: + case OPC_SUBU_QH: + case OPC_SUBU_S_QH: + case OPC_SUBUH_OB: + case OPC_SUBUH_R_OB: + case OPC_ADDQ_PW: + case OPC_ADDQ_S_PW: + case OPC_ADDQ_QH: + case OPC_ADDQ_S_QH: + case OPC_ADDU_OB: + case OPC_ADDU_S_OB: + case OPC_ADDU_QH: + case OPC_ADDU_S_QH: + case OPC_ADDUH_OB: + case OPC_ADDUH_R_OB: + gen_mipsdsp_arith(ctx, op1, op2, rd, rs, rt); + break; + case OPC_MULEQ_S_PW_QHL: + case OPC_MULEQ_S_PW_QHR: + case OPC_MULEU_S_QH_OBL: + case OPC_MULEU_S_QH_OBR: + case OPC_MULQ_RS_QH: + gen_mipsdsp_multiply(ctx, op1, op2, rd, rs, rt, 1); + break; + default: /* Invalid */ + MIPS_INVAL("MASK ADDU.OB"); + generate_exception(ctx, EXCP_RI); + break; + } + break; + case OPC_CMPU_EQ_OB_DSP: + op2 = MASK_CMPU_EQ_OB(ctx->opcode); + switch (op2) { + case OPC_PRECR_SRA_QH_PW: + case OPC_PRECR_SRA_R_QH_PW: + /* Return value is rt. */ + gen_mipsdsp_arith(ctx, op1, op2, rt, rs, rd); + break; + case OPC_PRECR_OB_QH: + case OPC_PRECRQ_OB_QH: + case OPC_PRECRQ_PW_L: + case OPC_PRECRQ_QH_PW: + case OPC_PRECRQ_RS_QH_PW: + case OPC_PRECRQU_S_OB_QH: + gen_mipsdsp_arith(ctx, op1, op2, rd, rs, rt); + break; + case OPC_CMPU_EQ_OB: + case OPC_CMPU_LT_OB: + case OPC_CMPU_LE_OB: + case OPC_CMP_EQ_QH: + case OPC_CMP_LT_QH: + case OPC_CMP_LE_QH: + case OPC_CMP_EQ_PW: + case OPC_CMP_LT_PW: + case OPC_CMP_LE_PW: + gen_mipsdsp_add_cmp_pick(ctx, op1, op2, rd, rs, rt, 0); + break; + case OPC_CMPGDU_EQ_OB: + case OPC_CMPGDU_LT_OB: + case OPC_CMPGDU_LE_OB: + case OPC_CMPGU_EQ_OB: + case OPC_CMPGU_LT_OB: + case OPC_CMPGU_LE_OB: + case OPC_PACKRL_PW: + case OPC_PICK_OB: + case OPC_PICK_PW: + case OPC_PICK_QH: + gen_mipsdsp_add_cmp_pick(ctx, op1, op2, rd, rs, rt, 1); + break; + default: /* Invalid */ + MIPS_INVAL("MASK CMPU_EQ.OB"); + generate_exception(ctx, EXCP_RI); + break; + } + break; + case OPC_DAPPEND_DSP: + gen_mipsdsp_append(env, ctx, op1, rt, rs, rd); + break; + case OPC_DEXTR_W_DSP: + op2 = MASK_DEXTR_W(ctx->opcode); + switch (op2) { + case OPC_DEXTP: + case OPC_DEXTPDP: + case OPC_DEXTPDPV: + case OPC_DEXTPV: + case OPC_DEXTR_L: + case OPC_DEXTR_R_L: + case OPC_DEXTR_RS_L: + case OPC_DEXTR_W: + case OPC_DEXTR_R_W: + case OPC_DEXTR_RS_W: + case OPC_DEXTR_S_H: + case OPC_DEXTRV_L: + case OPC_DEXTRV_R_L: + case OPC_DEXTRV_RS_L: + case OPC_DEXTRV_S_H: + case OPC_DEXTRV_W: + case OPC_DEXTRV_R_W: + case OPC_DEXTRV_RS_W: + gen_mipsdsp_accinsn(ctx, op1, op2, rt, rs, rd, 1); + break; + case OPC_DMTHLIP: + case OPC_DSHILO: + case OPC_DSHILOV: + gen_mipsdsp_accinsn(ctx, op1, op2, rd, rs, rt, 0); + break; + default: /* Invalid */ + MIPS_INVAL("MASK EXTR.W"); + generate_exception(ctx, EXCP_RI); + break; + } + break; + case OPC_DPAQ_W_QH_DSP: + op2 = MASK_DPAQ_W_QH(ctx->opcode); + switch (op2) { + case OPC_DPAU_H_OBL: + case OPC_DPAU_H_OBR: + case OPC_DPSU_H_OBL: + case OPC_DPSU_H_OBR: + case OPC_DPA_W_QH: + case OPC_DPAQ_S_W_QH: + case OPC_DPS_W_QH: + case OPC_DPSQ_S_W_QH: + case OPC_MULSAQ_S_W_QH: + case OPC_DPAQ_SA_L_PW: + case OPC_DPSQ_SA_L_PW: + case OPC_MULSAQ_S_L_PW: + gen_mipsdsp_multiply(ctx, op1, op2, rd, rs, rt, 0); + break; + case OPC_MAQ_S_W_QHLL: + case OPC_MAQ_S_W_QHLR: + case OPC_MAQ_S_W_QHRL: + case OPC_MAQ_S_W_QHRR: + case OPC_MAQ_SA_W_QHLL: + case OPC_MAQ_SA_W_QHLR: + case OPC_MAQ_SA_W_QHRL: + case OPC_MAQ_SA_W_QHRR: + case OPC_MAQ_S_L_PWL: + case OPC_MAQ_S_L_PWR: + case OPC_DMADD: + case OPC_DMADDU: + case OPC_DMSUB: + case OPC_DMSUBU: + gen_mipsdsp_multiply(ctx, op1, op2, rd, rs, rt, 0); + break; + default: /* Invalid */ + MIPS_INVAL("MASK DPAQ.W.QH"); + generate_exception(ctx, EXCP_RI); + break; + } + break; + case OPC_DINSV_DSP: + op2 = MASK_INSV(ctx->opcode); + switch (op2) { + case OPC_DINSV: + { + TCGv t0, t1; + + if (rt == 0) { + MIPS_DEBUG("NOP"); + break; + } + check_dsp(ctx); + + t0 = tcg_temp_new(); + t1 = tcg_temp_new(); + + gen_load_gpr(t0, rt); + gen_load_gpr(t1, rs); + + gen_helper_dinsv(cpu_gpr[rt], cpu_env, t1, t0); + + tcg_temp_free(t0); + tcg_temp_free(t1); + break; + } + default: /* Invalid */ + MIPS_INVAL("MASK DINSV"); + generate_exception(ctx, EXCP_RI); + break; + } + break; + case OPC_SHLL_OB_DSP: + gen_mipsdsp_shift(ctx, op1, rd, rs, rt); + break; +#endif + default: /* Invalid */ + MIPS_INVAL("special3"); + generate_exception(ctx, EXCP_RI); + break; + } +} + static void decode_opc (CPUMIPSState *env, DisasContext *ctx) { int32_t offset; int rs, rt, rd, sa; - uint32_t op, op1, op2; + uint32_t op, op1; int16_t imm; /* make sure instructions are on a word boundary */ @@ -14519,873 +15418,13 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx) imm = (int16_t)ctx->opcode; switch (op) { case OPC_SPECIAL: - op1 = MASK_SPECIAL(ctx->opcode); - switch (op1) { - case OPC_SLL: /* Shift with immediate */ - case OPC_SRA: - gen_shift_imm(ctx, op1, rd, rt, sa); - break; - case OPC_SRL: - switch ((ctx->opcode >> 21) & 0x1f) { - case 1: - /* rotr is decoded as srl on non-R2 CPUs */ - if (ctx->insn_flags & ISA_MIPS32R2) { - op1 = OPC_ROTR; - } - /* Fallthrough */ - case 0: - gen_shift_imm(ctx, op1, rd, rt, sa); - break; - default: - generate_exception(ctx, EXCP_RI); - break; - } - break; - case OPC_MOVN: /* Conditional move */ - case OPC_MOVZ: - check_insn_opc_removed(ctx, ISA_MIPS32R6); - check_insn(ctx, ISA_MIPS4 | ISA_MIPS32 | - INSN_LOONGSON2E | INSN_LOONGSON2F); - gen_cond_move(ctx, op1, rd, rs, rt); - break; - case OPC_SELEQZ: - case OPC_SELNEZ: - check_insn(ctx, ISA_MIPS32R6); - gen_cond_move(ctx, op1, rd, rs, rt); - break; - case OPC_ADD ... OPC_SUBU: - gen_arith(ctx, op1, rd, rs, rt); - break; - case OPC_SLLV: /* Shifts */ - case OPC_SRAV: - gen_shift(ctx, op1, rd, rs, rt); - break; - case OPC_SRLV: - switch ((ctx->opcode >> 6) & 0x1f) { - case 1: - /* rotrv is decoded as srlv on non-R2 CPUs */ - if (ctx->insn_flags & ISA_MIPS32R2) { - op1 = OPC_ROTRV; - } - /* Fallthrough */ - case 0: - gen_shift(ctx, op1, rd, rs, rt); - break; - default: - generate_exception(ctx, EXCP_RI); - break; - } - break; - case OPC_SLT: /* Set on less than */ - case OPC_SLTU: - gen_slt(ctx, op1, rd, rs, rt); - break; - case OPC_AND: /* Logic*/ - case OPC_OR: - case OPC_NOR: - case OPC_XOR: - gen_logic(ctx, op1, rd, rs, rt); - break; - case OPC_MULT: - case OPC_MULTU: - if (sa) { - check_insn(ctx, INSN_VR54XX); - op1 = MASK_MUL_VR54XX(ctx->opcode); - gen_mul_vr54xx(ctx, op1, rd, rs, rt); - } else { - gen_muldiv(ctx, op1, rd & 3, rs, rt); - } - break; - case OPC_DIV: - case OPC_DIVU: - gen_muldiv(ctx, op1, 0, rs, rt); - break; - case OPC_JR ... OPC_JALR: - gen_compute_branch(ctx, op1, 4, rs, rd, sa); - break; - case OPC_TGE ... OPC_TEQ: /* Traps */ - case OPC_TNE: - gen_trap(ctx, op1, rs, rt, -1); - break; - case OPC_MFHI: /* Move from HI/LO */ - case OPC_MFLO: - check_insn_opc_removed(ctx, ISA_MIPS32R6); - gen_HILO(ctx, op1, rs & 3, rd); - break; - case OPC_MTHI: - case OPC_MTLO: /* Move to HI/LO */ - check_insn_opc_removed(ctx, ISA_MIPS32R6); - gen_HILO(ctx, op1, rd & 3, rs); - break; - case OPC_PMON: /* Pmon entry point, also R4010 selsl */ -#ifdef MIPS_STRICT_STANDARD - MIPS_INVAL("PMON / selsl"); - generate_exception(ctx, EXCP_RI); -#else - gen_helper_0e0i(pmon, sa); -#endif - break; - case OPC_SYSCALL: - generate_exception(ctx, EXCP_SYSCALL); - ctx->bstate = BS_STOP; - break; - case OPC_BREAK: - generate_exception(ctx, EXCP_BREAK); - break; - case OPC_SPIM: -#ifdef MIPS_STRICT_STANDARD - MIPS_INVAL("SPIM"); - generate_exception(ctx, EXCP_RI); -#else - /* Implemented as RI exception for now. */ - MIPS_INVAL("spim (unofficial)"); - generate_exception(ctx, EXCP_RI); -#endif - break; - case OPC_SYNC: - /* Treat as NOP. */ - break; - - case OPC_MOVCI: - check_insn_opc_removed(ctx, ISA_MIPS32R6); - check_insn(ctx, ISA_MIPS4 | ISA_MIPS32); - if (ctx->CP0_Config1 & (1 << CP0C1_FP)) { - check_cp1_enabled(ctx); - gen_movci(ctx, rd, rs, (ctx->opcode >> 18) & 0x7, - (ctx->opcode >> 16) & 1); - } else { - generate_exception_err(ctx, EXCP_CpU, 1); - } - break; - -#if defined(TARGET_MIPS64) - /* MIPS64 specific opcodes */ - case OPC_DSLL: - case OPC_DSRA: - case OPC_DSLL32: - case OPC_DSRA32: - check_insn(ctx, ISA_MIPS3); - check_mips_64(ctx); - gen_shift_imm(ctx, op1, rd, rt, sa); - break; - case OPC_DSRL: - switch ((ctx->opcode >> 21) & 0x1f) { - case 1: - /* drotr is decoded as dsrl on non-R2 CPUs */ - if (ctx->insn_flags & ISA_MIPS32R2) { - op1 = OPC_DROTR; - } - /* Fallthrough */ - case 0: - check_insn(ctx, ISA_MIPS3); - check_mips_64(ctx); - gen_shift_imm(ctx, op1, rd, rt, sa); - break; - default: - generate_exception(ctx, EXCP_RI); - break; - } - break; - case OPC_DSRL32: - switch ((ctx->opcode >> 21) & 0x1f) { - case 1: - /* drotr32 is decoded as dsrl32 on non-R2 CPUs */ - if (ctx->insn_flags & ISA_MIPS32R2) { - op1 = OPC_DROTR32; - } - /* Fallthrough */ - case 0: - check_insn(ctx, ISA_MIPS3); - check_mips_64(ctx); - gen_shift_imm(ctx, op1, rd, rt, sa); - break; - default: - generate_exception(ctx, EXCP_RI); - break; - } - break; - case OPC_DADD ... OPC_DSUBU: - check_insn(ctx, ISA_MIPS3); - check_mips_64(ctx); - gen_arith(ctx, op1, rd, rs, rt); - break; - case OPC_DSLLV: - case OPC_DSRAV: - check_insn(ctx, ISA_MIPS3); - check_mips_64(ctx); - gen_shift(ctx, op1, rd, rs, rt); - break; - case OPC_DSRLV: - switch ((ctx->opcode >> 6) & 0x1f) { - case 1: - /* drotrv is decoded as dsrlv on non-R2 CPUs */ - if (ctx->insn_flags & ISA_MIPS32R2) { - op1 = OPC_DROTRV; - } - /* Fallthrough */ - case 0: - check_insn(ctx, ISA_MIPS3); - check_mips_64(ctx); - gen_shift(ctx, op1, rd, rs, rt); - break; - default: - generate_exception(ctx, EXCP_RI); - break; - } - break; - case OPC_DMULT ... OPC_DDIVU: - check_insn(ctx, ISA_MIPS3); - check_mips_64(ctx); - gen_muldiv(ctx, op1, 0, rs, rt); - break; -#endif - default: /* Invalid */ - MIPS_INVAL("special"); - generate_exception(ctx, EXCP_RI); - break; - } + decode_opc_special(env, ctx); break; case OPC_SPECIAL2: - op1 = MASK_SPECIAL2(ctx->opcode); - switch (op1) { - case OPC_MADD ... OPC_MADDU: /* Multiply and add/sub */ - case OPC_MSUB ... OPC_MSUBU: - check_insn_opc_removed(ctx, ISA_MIPS32R6); - check_insn(ctx, ISA_MIPS32); - gen_muldiv(ctx, op1, rd & 3, rs, rt); - break; - case OPC_MUL: - check_insn_opc_removed(ctx, ISA_MIPS32R6); - gen_arith(ctx, op1, rd, rs, rt); - break; - case OPC_CLO: - case OPC_CLZ: - check_insn(ctx, ISA_MIPS32); - gen_cl(ctx, op1, rd, rs); - break; - case OPC_SDBBP: - /* XXX: not clear which exception should be raised - * when in debug mode... - */ - check_insn(ctx, ISA_MIPS32); - if (!(ctx->hflags & MIPS_HFLAG_DM)) { - generate_exception(ctx, EXCP_DBp); - } else { - generate_exception(ctx, EXCP_DBp); - } - /* Treat as NOP. */ - 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(ctx, INSN_LOONGSON2F); - gen_loongson_integer(ctx, op1, rd, rs, rt); - break; -#if defined(TARGET_MIPS64) - case OPC_DCLO: - case OPC_DCLZ: - check_insn(ctx, ISA_MIPS64); - 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: - case OPC_DMOD_G_2F: - case OPC_DMODU_G_2F: - check_insn(ctx, INSN_LOONGSON2F); - gen_loongson_integer(ctx, op1, rd, rs, rt); - break; -#endif - default: /* Invalid */ - MIPS_INVAL("special2"); - generate_exception(ctx, EXCP_RI); - break; - } + decode_opc_special2(env, ctx); break; case OPC_SPECIAL3: - op1 = MASK_SPECIAL3(ctx->opcode); - switch (op1) { - case R6_OPC_LL: - check_insn(ctx, ISA_MIPS32R6); - gen_ld(ctx, op1, rt, rs, imm >> 7); - break; - case OPC_EXT: - case OPC_INS: - check_insn(ctx, ISA_MIPS32R2); - gen_bitops(ctx, op1, rt, rs, sa, rd); - break; - case OPC_BSHFL: - check_insn(ctx, ISA_MIPS32R2); - op2 = MASK_BSHFL(ctx->opcode); - gen_bshfl(ctx, op2, rt, rd); - break; - case OPC_RDHWR: - gen_rdhwr(ctx, rt, rd); - break; - case OPC_FORK: - check_insn(ctx, ASE_MT); - { - TCGv t0 = tcg_temp_new(); - TCGv t1 = tcg_temp_new(); - - gen_load_gpr(t0, rt); - gen_load_gpr(t1, rs); - gen_helper_fork(t0, t1); - tcg_temp_free(t0); - tcg_temp_free(t1); - } - break; - case OPC_YIELD: - check_insn(ctx, ASE_MT); - { - TCGv t0 = tcg_temp_new(); - - save_cpu_state(ctx, 1); - gen_load_gpr(t0, rs); - gen_helper_yield(t0, cpu_env, t0); - gen_store_gpr(t0, rd); - tcg_temp_free(t0); - } - break; - case OPC_DIV_G_2E ... OPC_DIVU_G_2E: - case OPC_MOD_G_2E ... OPC_MODU_G_2E: - case OPC_MULT_G_2E ... OPC_MULTU_G_2E: - /* OPC_MULT_G_2E, OPC_ADDUH_QB_DSP, OPC_MUL_PH_DSP have - * the same mask and op1. */ - if ((ctx->insn_flags & ASE_DSPR2) && (op1 == OPC_MULT_G_2E)) { - op2 = MASK_ADDUH_QB(ctx->opcode); - switch (op2) { - case OPC_ADDUH_QB: - case OPC_ADDUH_R_QB: - case OPC_ADDQH_PH: - case OPC_ADDQH_R_PH: - case OPC_ADDQH_W: - case OPC_ADDQH_R_W: - case OPC_SUBUH_QB: - case OPC_SUBUH_R_QB: - case OPC_SUBQH_PH: - case OPC_SUBQH_R_PH: - case OPC_SUBQH_W: - case OPC_SUBQH_R_W: - gen_mipsdsp_arith(ctx, op1, op2, rd, rs, rt); - break; - case OPC_MUL_PH: - case OPC_MUL_S_PH: - case OPC_MULQ_S_W: - case OPC_MULQ_RS_W: - gen_mipsdsp_multiply(ctx, op1, op2, rd, rs, rt, 1); - break; - default: - MIPS_INVAL("MASK ADDUH.QB"); - generate_exception(ctx, EXCP_RI); - break; - } - } else if (ctx->insn_flags & INSN_LOONGSON2E) { - gen_loongson_integer(ctx, op1, rd, rs, rt); - } else { - generate_exception(ctx, EXCP_RI); - } - break; - case OPC_LX_DSP: - op2 = MASK_LX(ctx->opcode); - switch (op2) { -#if defined(TARGET_MIPS64) - case OPC_LDX: -#endif - case OPC_LBUX: - case OPC_LHX: - case OPC_LWX: - gen_mipsdsp_ld(ctx, op2, rd, rs, rt); - break; - default: /* Invalid */ - MIPS_INVAL("MASK LX"); - generate_exception(ctx, EXCP_RI); - break; - } - break; - case OPC_ABSQ_S_PH_DSP: - op2 = MASK_ABSQ_S_PH(ctx->opcode); - switch (op2) { - case OPC_ABSQ_S_QB: - case OPC_ABSQ_S_PH: - case OPC_ABSQ_S_W: - case OPC_PRECEQ_W_PHL: - case OPC_PRECEQ_W_PHR: - case OPC_PRECEQU_PH_QBL: - case OPC_PRECEQU_PH_QBR: - case OPC_PRECEQU_PH_QBLA: - case OPC_PRECEQU_PH_QBRA: - case OPC_PRECEU_PH_QBL: - case OPC_PRECEU_PH_QBR: - case OPC_PRECEU_PH_QBLA: - case OPC_PRECEU_PH_QBRA: - gen_mipsdsp_arith(ctx, op1, op2, rd, rs, rt); - break; - case OPC_BITREV: - case OPC_REPL_QB: - case OPC_REPLV_QB: - case OPC_REPL_PH: - case OPC_REPLV_PH: - gen_mipsdsp_bitinsn(ctx, op1, op2, rd, rt); - break; - default: - MIPS_INVAL("MASK ABSQ_S.PH"); - generate_exception(ctx, EXCP_RI); - break; - } - break; - case OPC_ADDU_QB_DSP: - op2 = MASK_ADDU_QB(ctx->opcode); - switch (op2) { - case OPC_ADDQ_PH: - case OPC_ADDQ_S_PH: - case OPC_ADDQ_S_W: - case OPC_ADDU_QB: - case OPC_ADDU_S_QB: - case OPC_ADDU_PH: - case OPC_ADDU_S_PH: - case OPC_SUBQ_PH: - case OPC_SUBQ_S_PH: - case OPC_SUBQ_S_W: - case OPC_SUBU_QB: - case OPC_SUBU_S_QB: - case OPC_SUBU_PH: - case OPC_SUBU_S_PH: - case OPC_ADDSC: - case OPC_ADDWC: - case OPC_MODSUB: - case OPC_RADDU_W_QB: - gen_mipsdsp_arith(ctx, op1, op2, rd, rs, rt); - break; - case OPC_MULEU_S_PH_QBL: - case OPC_MULEU_S_PH_QBR: - case OPC_MULQ_RS_PH: - case OPC_MULEQ_S_W_PHL: - case OPC_MULEQ_S_W_PHR: - case OPC_MULQ_S_PH: - gen_mipsdsp_multiply(ctx, op1, op2, rd, rs, rt, 1); - break; - default: /* Invalid */ - MIPS_INVAL("MASK ADDU.QB"); - generate_exception(ctx, EXCP_RI); - break; - - } - break; - case OPC_CMPU_EQ_QB_DSP: - op2 = MASK_CMPU_EQ_QB(ctx->opcode); - switch (op2) { - case OPC_PRECR_SRA_PH_W: - case OPC_PRECR_SRA_R_PH_W: - gen_mipsdsp_arith(ctx, op1, op2, rt, rs, rd); - break; - case OPC_PRECR_QB_PH: - case OPC_PRECRQ_QB_PH: - case OPC_PRECRQ_PH_W: - case OPC_PRECRQ_RS_PH_W: - case OPC_PRECRQU_S_QB_PH: - gen_mipsdsp_arith(ctx, op1, op2, rd, rs, rt); - break; - case OPC_CMPU_EQ_QB: - case OPC_CMPU_LT_QB: - case OPC_CMPU_LE_QB: - case OPC_CMP_EQ_PH: - case OPC_CMP_LT_PH: - case OPC_CMP_LE_PH: - gen_mipsdsp_add_cmp_pick(ctx, op1, op2, rd, rs, rt, 0); - break; - case OPC_CMPGU_EQ_QB: - case OPC_CMPGU_LT_QB: - case OPC_CMPGU_LE_QB: - case OPC_CMPGDU_EQ_QB: - case OPC_CMPGDU_LT_QB: - case OPC_CMPGDU_LE_QB: - case OPC_PICK_QB: - case OPC_PICK_PH: - case OPC_PACKRL_PH: - gen_mipsdsp_add_cmp_pick(ctx, op1, op2, rd, rs, rt, 1); - break; - default: /* Invalid */ - MIPS_INVAL("MASK CMPU.EQ.QB"); - generate_exception(ctx, EXCP_RI); - break; - } - break; - case OPC_SHLL_QB_DSP: - gen_mipsdsp_shift(ctx, op1, rd, rs, rt); - break; - case OPC_DPA_W_PH_DSP: - op2 = MASK_DPA_W_PH(ctx->opcode); - switch (op2) { - case OPC_DPAU_H_QBL: - case OPC_DPAU_H_QBR: - case OPC_DPSU_H_QBL: - case OPC_DPSU_H_QBR: - case OPC_DPA_W_PH: - case OPC_DPAX_W_PH: - case OPC_DPAQ_S_W_PH: - case OPC_DPAQX_S_W_PH: - case OPC_DPAQX_SA_W_PH: - case OPC_DPS_W_PH: - case OPC_DPSX_W_PH: - case OPC_DPSQ_S_W_PH: - case OPC_DPSQX_S_W_PH: - case OPC_DPSQX_SA_W_PH: - case OPC_MULSAQ_S_W_PH: - case OPC_DPAQ_SA_L_W: - case OPC_DPSQ_SA_L_W: - case OPC_MAQ_S_W_PHL: - case OPC_MAQ_S_W_PHR: - case OPC_MAQ_SA_W_PHL: - case OPC_MAQ_SA_W_PHR: - case OPC_MULSA_W_PH: - gen_mipsdsp_multiply(ctx, op1, op2, rd, rs, rt, 0); - break; - default: /* Invalid */ - MIPS_INVAL("MASK DPAW.PH"); - generate_exception(ctx, EXCP_RI); - break; - } - break; - case OPC_INSV_DSP: - op2 = MASK_INSV(ctx->opcode); - switch (op2) { - case OPC_INSV: - check_dsp(ctx); - { - TCGv t0, t1; - - if (rt == 0) { - MIPS_DEBUG("NOP"); - break; - } - - t0 = tcg_temp_new(); - t1 = tcg_temp_new(); - - gen_load_gpr(t0, rt); - gen_load_gpr(t1, rs); - - gen_helper_insv(cpu_gpr[rt], cpu_env, t1, t0); - - tcg_temp_free(t0); - tcg_temp_free(t1); - break; - } - default: /* Invalid */ - MIPS_INVAL("MASK INSV"); - generate_exception(ctx, EXCP_RI); - break; - } - break; - case OPC_APPEND_DSP: - gen_mipsdsp_append(env, ctx, op1, rt, rs, rd); - break; - case OPC_EXTR_W_DSP: - op2 = MASK_EXTR_W(ctx->opcode); - switch (op2) { - case OPC_EXTR_W: - case OPC_EXTR_R_W: - case OPC_EXTR_RS_W: - case OPC_EXTR_S_H: - case OPC_EXTRV_S_H: - case OPC_EXTRV_W: - case OPC_EXTRV_R_W: - case OPC_EXTRV_RS_W: - case OPC_EXTP: - case OPC_EXTPV: - case OPC_EXTPDP: - case OPC_EXTPDPV: - gen_mipsdsp_accinsn(ctx, op1, op2, rt, rs, rd, 1); - break; - case OPC_RDDSP: - gen_mipsdsp_accinsn(ctx, op1, op2, rd, rs, rt, 1); - break; - case OPC_SHILO: - case OPC_SHILOV: - case OPC_MTHLIP: - case OPC_WRDSP: - gen_mipsdsp_accinsn(ctx, op1, op2, rd, rs, rt, 0); - break; - default: /* Invalid */ - MIPS_INVAL("MASK EXTR.W"); - generate_exception(ctx, EXCP_RI); - break; - } - break; - case R6_OPC_SC: /* OPC_DMOD_G_2E */ - if (ctx->insn_flags & ISA_MIPS32R6) { - gen_st_cond(ctx, op1, rt, rs, imm >> 7); - } else { -#if defined(TARGET_MIPS64) - check_insn(ctx, INSN_LOONGSON2E); - gen_loongson_integer(ctx, op1, rd, rs, rt); -#else - /* Invalid in MIPS32 */ - generate_exception(ctx, EXCP_RI); -#endif - } - break; -#if defined(TARGET_MIPS64) - case OPC_DEXTM ... OPC_DEXT: - case OPC_DINSM ... OPC_DINS: - check_insn(ctx, ISA_MIPS64R2); - check_mips_64(ctx); - gen_bitops(ctx, op1, rt, rs, sa, rd); - break; - case OPC_DBSHFL: - check_insn(ctx, ISA_MIPS64R2); - check_mips_64(ctx); - op2 = MASK_DBSHFL(ctx->opcode); - gen_bshfl(ctx, op2, rt, rd); - break; - case OPC_DDIV_G_2E ... OPC_DDIVU_G_2E: - case OPC_DMULT_G_2E ... OPC_DMULTU_G_2E: - case OPC_DMODU_G_2E: - check_insn(ctx, INSN_LOONGSON2E); - gen_loongson_integer(ctx, op1, rd, rs, rt); - break; - case OPC_ABSQ_S_QH_DSP: - op2 = MASK_ABSQ_S_QH(ctx->opcode); - switch (op2) { - case OPC_PRECEQ_L_PWL: - case OPC_PRECEQ_L_PWR: - case OPC_PRECEQ_PW_QHL: - case OPC_PRECEQ_PW_QHR: - case OPC_PRECEQ_PW_QHLA: - case OPC_PRECEQ_PW_QHRA: - case OPC_PRECEQU_QH_OBL: - case OPC_PRECEQU_QH_OBR: - case OPC_PRECEQU_QH_OBLA: - case OPC_PRECEQU_QH_OBRA: - case OPC_PRECEU_QH_OBL: - case OPC_PRECEU_QH_OBR: - case OPC_PRECEU_QH_OBLA: - case OPC_PRECEU_QH_OBRA: - case OPC_ABSQ_S_OB: - case OPC_ABSQ_S_PW: - case OPC_ABSQ_S_QH: - gen_mipsdsp_arith(ctx, op1, op2, rd, rs, rt); - break; - case OPC_REPL_OB: - case OPC_REPL_PW: - case OPC_REPL_QH: - case OPC_REPLV_OB: - case OPC_REPLV_PW: - case OPC_REPLV_QH: - gen_mipsdsp_bitinsn(ctx, op1, op2, rd, rt); - break; - default: /* Invalid */ - MIPS_INVAL("MASK ABSQ_S.QH"); - generate_exception(ctx, EXCP_RI); - break; - } - break; - case OPC_ADDU_OB_DSP: - op2 = MASK_ADDU_OB(ctx->opcode); - switch (op2) { - case OPC_RADDU_L_OB: - case OPC_SUBQ_PW: - case OPC_SUBQ_S_PW: - case OPC_SUBQ_QH: - case OPC_SUBQ_S_QH: - case OPC_SUBU_OB: - case OPC_SUBU_S_OB: - case OPC_SUBU_QH: - case OPC_SUBU_S_QH: - case OPC_SUBUH_OB: - case OPC_SUBUH_R_OB: - case OPC_ADDQ_PW: - case OPC_ADDQ_S_PW: - case OPC_ADDQ_QH: - case OPC_ADDQ_S_QH: - case OPC_ADDU_OB: - case OPC_ADDU_S_OB: - case OPC_ADDU_QH: - case OPC_ADDU_S_QH: - case OPC_ADDUH_OB: - case OPC_ADDUH_R_OB: - gen_mipsdsp_arith(ctx, op1, op2, rd, rs, rt); - break; - case OPC_MULEQ_S_PW_QHL: - case OPC_MULEQ_S_PW_QHR: - case OPC_MULEU_S_QH_OBL: - case OPC_MULEU_S_QH_OBR: - case OPC_MULQ_RS_QH: - gen_mipsdsp_multiply(ctx, op1, op2, rd, rs, rt, 1); - break; - default: /* Invalid */ - MIPS_INVAL("MASK ADDU.OB"); - generate_exception(ctx, EXCP_RI); - break; - } - break; - case OPC_CMPU_EQ_OB_DSP: - op2 = MASK_CMPU_EQ_OB(ctx->opcode); - switch (op2) { - case OPC_PRECR_SRA_QH_PW: - case OPC_PRECR_SRA_R_QH_PW: - /* Return value is rt. */ - gen_mipsdsp_arith(ctx, op1, op2, rt, rs, rd); - break; - case OPC_PRECR_OB_QH: - case OPC_PRECRQ_OB_QH: - case OPC_PRECRQ_PW_L: - case OPC_PRECRQ_QH_PW: - case OPC_PRECRQ_RS_QH_PW: - case OPC_PRECRQU_S_OB_QH: - gen_mipsdsp_arith(ctx, op1, op2, rd, rs, rt); - break; - case OPC_CMPU_EQ_OB: - case OPC_CMPU_LT_OB: - case OPC_CMPU_LE_OB: - case OPC_CMP_EQ_QH: - case OPC_CMP_LT_QH: - case OPC_CMP_LE_QH: - case OPC_CMP_EQ_PW: - case OPC_CMP_LT_PW: - case OPC_CMP_LE_PW: - gen_mipsdsp_add_cmp_pick(ctx, op1, op2, rd, rs, rt, 0); - break; - case OPC_CMPGDU_EQ_OB: - case OPC_CMPGDU_LT_OB: - case OPC_CMPGDU_LE_OB: - case OPC_CMPGU_EQ_OB: - case OPC_CMPGU_LT_OB: - case OPC_CMPGU_LE_OB: - case OPC_PACKRL_PW: - case OPC_PICK_OB: - case OPC_PICK_PW: - case OPC_PICK_QH: - gen_mipsdsp_add_cmp_pick(ctx, op1, op2, rd, rs, rt, 1); - break; - default: /* Invalid */ - MIPS_INVAL("MASK CMPU_EQ.OB"); - generate_exception(ctx, EXCP_RI); - break; - } - break; - case OPC_DAPPEND_DSP: - gen_mipsdsp_append(env, ctx, op1, rt, rs, rd); - break; - case OPC_DEXTR_W_DSP: - op2 = MASK_DEXTR_W(ctx->opcode); - switch (op2) { - case OPC_DEXTP: - case OPC_DEXTPDP: - case OPC_DEXTPDPV: - case OPC_DEXTPV: - case OPC_DEXTR_L: - case OPC_DEXTR_R_L: - case OPC_DEXTR_RS_L: - case OPC_DEXTR_W: - case OPC_DEXTR_R_W: - case OPC_DEXTR_RS_W: - case OPC_DEXTR_S_H: - case OPC_DEXTRV_L: - case OPC_DEXTRV_R_L: - case OPC_DEXTRV_RS_L: - case OPC_DEXTRV_S_H: - case OPC_DEXTRV_W: - case OPC_DEXTRV_R_W: - case OPC_DEXTRV_RS_W: - gen_mipsdsp_accinsn(ctx, op1, op2, rt, rs, rd, 1); - break; - case OPC_DMTHLIP: - case OPC_DSHILO: - case OPC_DSHILOV: - gen_mipsdsp_accinsn(ctx, op1, op2, rd, rs, rt, 0); - break; - default: /* Invalid */ - MIPS_INVAL("MASK EXTR.W"); - generate_exception(ctx, EXCP_RI); - break; - } - break; - case OPC_DPAQ_W_QH_DSP: - op2 = MASK_DPAQ_W_QH(ctx->opcode); - switch (op2) { - case OPC_DPAU_H_OBL: - case OPC_DPAU_H_OBR: - case OPC_DPSU_H_OBL: - case OPC_DPSU_H_OBR: - case OPC_DPA_W_QH: - case OPC_DPAQ_S_W_QH: - case OPC_DPS_W_QH: - case OPC_DPSQ_S_W_QH: - case OPC_MULSAQ_S_W_QH: - case OPC_DPAQ_SA_L_PW: - case OPC_DPSQ_SA_L_PW: - case OPC_MULSAQ_S_L_PW: - gen_mipsdsp_multiply(ctx, op1, op2, rd, rs, rt, 0); - break; - case OPC_MAQ_S_W_QHLL: - case OPC_MAQ_S_W_QHLR: - case OPC_MAQ_S_W_QHRL: - case OPC_MAQ_S_W_QHRR: - case OPC_MAQ_SA_W_QHLL: - case OPC_MAQ_SA_W_QHLR: - case OPC_MAQ_SA_W_QHRL: - case OPC_MAQ_SA_W_QHRR: - case OPC_MAQ_S_L_PWL: - case OPC_MAQ_S_L_PWR: - case OPC_DMADD: - case OPC_DMADDU: - case OPC_DMSUB: - case OPC_DMSUBU: - gen_mipsdsp_multiply(ctx, op1, op2, rd, rs, rt, 0); - break; - default: /* Invalid */ - MIPS_INVAL("MASK DPAQ.W.QH"); - generate_exception(ctx, EXCP_RI); - break; - } - break; - case OPC_DINSV_DSP: - op2 = MASK_INSV(ctx->opcode); - switch (op2) { - case OPC_DINSV: - { - TCGv t0, t1; - - if (rt == 0) { - MIPS_DEBUG("NOP"); - break; - } - check_dsp(ctx); - - t0 = tcg_temp_new(); - t1 = tcg_temp_new(); - - gen_load_gpr(t0, rt); - gen_load_gpr(t1, rs); - - gen_helper_dinsv(cpu_gpr[rt], cpu_env, t1, t0); - - tcg_temp_free(t0); - tcg_temp_free(t1); - break; - } - default: /* Invalid */ - MIPS_INVAL("MASK DINSV"); - generate_exception(ctx, EXCP_RI); - break; - } - break; - case OPC_SHLL_OB_DSP: - gen_mipsdsp_shift(ctx, op1, rd, rs, rt); - break; -#endif - default: /* Invalid */ - MIPS_INVAL("special3"); - generate_exception(ctx, EXCP_RI); - break; - } + decode_opc_special3(env, ctx); break; case OPC_REGIMM: op1 = MASK_REGIMM(ctx->opcode); @@ -15447,6 +15486,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx) case OPC_MFMC0: #ifndef CONFIG_USER_ONLY { + uint32_t op2; TCGv t0 = tcg_temp_new(); op2 = MASK_MFMC0(ctx->opcode); From 10dc65dbb83829590e79216a86c2ee168be3bf0b Mon Sep 17 00:00:00 2001 From: Leon Alrae Date: Fri, 27 Jun 2014 08:49:02 +0100 Subject: [PATCH 06/28] target-mips: split decode_opc_special* into *_r6 and *_legacy For better code readability and to avoid 'if' statements for all R6 and preR6 instructions whose opcodes are the same - decode_opc_special* functions are split into functions with _r6 and _legacy suffixes. *_r6 functions will contain instructions which were introduced in R6. *_legacy functions will contain instructions which were removed in R6. Signed-off-by: Leon Alrae Reviewed-by: Aurelien Jarno --- target-mips/translate.c | 242 +++++++++++++++++++++++++++------------- 1 file changed, 167 insertions(+), 75 deletions(-) diff --git a/target-mips/translate.c b/target-mips/translate.c index 5b8f762ec6..0c64aeb87d 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -14482,6 +14482,70 @@ static void gen_mipsdsp_accinsn(DisasContext *ctx, uint32_t op1, uint32_t op2, /* End MIPSDSP functions. */ +static void decode_opc_special_r6(CPUMIPSState *env, DisasContext *ctx) +{ + int rs, rt, rd; + uint32_t op1; + + rs = (ctx->opcode >> 21) & 0x1f; + rt = (ctx->opcode >> 16) & 0x1f; + rd = (ctx->opcode >> 11) & 0x1f; + + op1 = MASK_SPECIAL(ctx->opcode); + switch (op1) { + case OPC_SELEQZ: + case OPC_SELNEZ: + gen_cond_move(ctx, op1, rd, rs, rt); + break; + default: /* Invalid */ + MIPS_INVAL("special_r6"); + generate_exception(ctx, EXCP_RI); + break; + } +} + +static void decode_opc_special_legacy(CPUMIPSState *env, DisasContext *ctx) +{ + int rs, rt, rd; + uint32_t op1; + + rs = (ctx->opcode >> 21) & 0x1f; + rt = (ctx->opcode >> 16) & 0x1f; + rd = (ctx->opcode >> 11) & 0x1f; + + op1 = MASK_SPECIAL(ctx->opcode); + switch (op1) { + case OPC_MOVN: /* Conditional move */ + case OPC_MOVZ: + check_insn(ctx, ISA_MIPS4 | ISA_MIPS32 | + INSN_LOONGSON2E | INSN_LOONGSON2F); + gen_cond_move(ctx, op1, rd, rs, rt); + break; + case OPC_MFHI: /* Move from HI/LO */ + case OPC_MFLO: + gen_HILO(ctx, op1, rs & 3, rd); + break; + case OPC_MTHI: + case OPC_MTLO: /* Move to HI/LO */ + gen_HILO(ctx, op1, rd & 3, rs); + break; + case OPC_MOVCI: + check_insn(ctx, ISA_MIPS4 | ISA_MIPS32); + if (env->CP0_Config1 & (1 << CP0C1_FP)) { + check_cp1_enabled(ctx); + gen_movci(ctx, rd, rs, (ctx->opcode >> 18) & 0x7, + (ctx->opcode >> 16) & 1); + } else { + generate_exception_err(ctx, EXCP_CpU, 1); + } + break; + default: /* Invalid */ + MIPS_INVAL("special_legacy"); + generate_exception(ctx, EXCP_RI); + break; + } +} + static void decode_opc_special(CPUMIPSState *env, DisasContext *ctx) { int rs, rt, rd, sa; @@ -14514,18 +14578,6 @@ static void decode_opc_special(CPUMIPSState *env, DisasContext *ctx) break; } break; - case OPC_MOVN: /* Conditional move */ - case OPC_MOVZ: - check_insn_opc_removed(ctx, ISA_MIPS32R6); - check_insn(ctx, ISA_MIPS4 | ISA_MIPS32 | - INSN_LOONGSON2E | INSN_LOONGSON2F); - gen_cond_move(ctx, op1, rd, rs, rt); - break; - case OPC_SELEQZ: - case OPC_SELNEZ: - check_insn(ctx, ISA_MIPS32R6); - gen_cond_move(ctx, op1, rd, rs, rt); - break; case OPC_ADD ... OPC_SUBU: gen_arith(ctx, op1, rd, rs, rt); break; @@ -14580,16 +14632,6 @@ static void decode_opc_special(CPUMIPSState *env, DisasContext *ctx) case OPC_TNE: gen_trap(ctx, op1, rs, rt, -1); break; - case OPC_MFHI: /* Move from HI/LO */ - case OPC_MFLO: - check_insn_opc_removed(ctx, ISA_MIPS32R6); - gen_HILO(ctx, op1, rs & 3, rd); - break; - case OPC_MTHI: - case OPC_MTLO: /* Move to HI/LO */ - check_insn_opc_removed(ctx, ISA_MIPS32R6); - gen_HILO(ctx, op1, rd & 3, rs); - break; case OPC_PMON: /* Pmon entry point, also R4010 selsl */ #ifdef MIPS_STRICT_STANDARD MIPS_INVAL("PMON / selsl"); @@ -14619,18 +14661,6 @@ static void decode_opc_special(CPUMIPSState *env, DisasContext *ctx) /* Treat as NOP. */ break; - case OPC_MOVCI: - check_insn_opc_removed(ctx, ISA_MIPS32R6); - check_insn(ctx, ISA_MIPS4 | ISA_MIPS32); - if (ctx->CP0_Config1 & (1 << CP0C1_FP)) { - check_cp1_enabled(ctx); - gen_movci(ctx, rd, rs, (ctx->opcode >> 18) & 0x7, - (ctx->opcode >> 16) & 1); - } else { - generate_exception_err(ctx, EXCP_CpU, 1); - } - break; - #if defined(TARGET_MIPS64) /* MIPS64 specific opcodes */ case OPC_DSLL: @@ -14712,8 +14742,49 @@ static void decode_opc_special(CPUMIPSState *env, DisasContext *ctx) gen_muldiv(ctx, op1, 0, rs, rt); break; #endif + default: + if (ctx->insn_flags & ISA_MIPS32R6) { + decode_opc_special_r6(env, ctx); + } else { + decode_opc_special_legacy(env, ctx); + } + } +} + +static void decode_opc_special2_r6(CPUMIPSState *env, DisasContext *ctx) +{ + uint32_t op1; + + op1 = MASK_SPECIAL2(ctx->opcode); + switch (op1) { default: /* Invalid */ - MIPS_INVAL("special"); + MIPS_INVAL("special2_r6"); + generate_exception(ctx, EXCP_RI); + break; + } +} + +static void decode_opc_special2_legacy(CPUMIPSState *env, DisasContext *ctx) +{ + int rs, rt, rd; + uint32_t op1; + + rs = (ctx->opcode >> 21) & 0x1f; + rt = (ctx->opcode >> 16) & 0x1f; + rd = (ctx->opcode >> 11) & 0x1f; + + op1 = MASK_SPECIAL2(ctx->opcode); + switch (op1) { + case OPC_MADD ... OPC_MADDU: /* Multiply and add/sub */ + case OPC_MSUB ... OPC_MSUBU: + check_insn(ctx, ISA_MIPS32); + gen_muldiv(ctx, op1, rd & 3, rs, rt); + break; + case OPC_MUL: + gen_arith(ctx, op1, rd, rs, rt); + break; + default: /* Invalid */ + MIPS_INVAL("special2_legacy"); generate_exception(ctx, EXCP_RI); break; } @@ -14730,16 +14801,6 @@ static void decode_opc_special2(CPUMIPSState *env, DisasContext *ctx) op1 = MASK_SPECIAL2(ctx->opcode); switch (op1) { - case OPC_MADD ... OPC_MADDU: /* Multiply and add/sub */ - case OPC_MSUB ... OPC_MSUBU: - check_insn_opc_removed(ctx, ISA_MIPS32R6); - check_insn(ctx, ISA_MIPS32); - gen_muldiv(ctx, op1, rd & 3, rs, rt); - break; - case OPC_MUL: - check_insn_opc_removed(ctx, ISA_MIPS32R6); - gen_arith(ctx, op1, rd, rs, rt); - break; case OPC_CLO: case OPC_CLZ: check_insn(ctx, ISA_MIPS32); @@ -14783,30 +14844,78 @@ static void decode_opc_special2(CPUMIPSState *env, DisasContext *ctx) gen_loongson_integer(ctx, op1, rd, rs, rt); break; #endif + default: + if (ctx->insn_flags & ISA_MIPS32R6) { + decode_opc_special2_r6(env, ctx); + } else { + decode_opc_special2_legacy(env, ctx); + } + } +} + +static void decode_opc_special3_r6(CPUMIPSState *env, DisasContext *ctx) +{ + int rs, rt; + uint32_t op1; + int16_t imm; + + rs = (ctx->opcode >> 21) & 0x1f; + rt = (ctx->opcode >> 16) & 0x1f; + imm = (int16_t)ctx->opcode >> 7; + + op1 = MASK_SPECIAL3(ctx->opcode); + switch (op1) { + case R6_OPC_SC: + gen_st_cond(ctx, op1, rt, rs, imm); + break; + case R6_OPC_LL: + gen_ld(ctx, op1, rt, rs, imm); + break; default: /* Invalid */ - MIPS_INVAL("special2"); + MIPS_INVAL("special3_r6"); generate_exception(ctx, EXCP_RI); break; } } + +static void decode_opc_special3_legacy(CPUMIPSState *env, DisasContext *ctx) +{ + uint32_t op1; +#if defined(TARGET_MIPS64) + int rd = (ctx->opcode >> 11) & 0x1f; + int rs = (ctx->opcode >> 21) & 0x1f; + int rt = (ctx->opcode >> 16) & 0x1f; +#endif + + op1 = MASK_SPECIAL3(ctx->opcode); + switch (op1) { +#if defined(TARGET_MIPS64) + case OPC_DDIV_G_2E ... OPC_DDIVU_G_2E: + case OPC_DMULT_G_2E ... OPC_DMULTU_G_2E: + case OPC_DMOD_G_2E ... OPC_DMODU_G_2E: + check_insn(ctx, INSN_LOONGSON2E); + gen_loongson_integer(ctx, op1, rd, rs, rt); + break; +#endif + default: /* Invalid */ + MIPS_INVAL("special3_legacy"); + generate_exception(ctx, EXCP_RI); + break; + } +} + static void decode_opc_special3(CPUMIPSState *env, DisasContext *ctx) { int rs, rt, rd, sa; uint32_t op1, op2; - int16_t imm; rs = (ctx->opcode >> 21) & 0x1f; rt = (ctx->opcode >> 16) & 0x1f; rd = (ctx->opcode >> 11) & 0x1f; sa = (ctx->opcode >> 6) & 0x1f; - imm = (int16_t)ctx->opcode; op1 = MASK_SPECIAL3(ctx->opcode); switch (op1) { - case R6_OPC_LL: - check_insn(ctx, ISA_MIPS32R6); - gen_ld(ctx, op1, rt, rs, imm >> 7); - break; case OPC_EXT: case OPC_INS: check_insn(ctx, ISA_MIPS32R2); @@ -15111,19 +15220,6 @@ static void decode_opc_special3(CPUMIPSState *env, DisasContext *ctx) break; } break; - case R6_OPC_SC: /* OPC_DMOD_G_2E */ - if (ctx->insn_flags & ISA_MIPS32R6) { - gen_st_cond(ctx, op1, rt, rs, imm >> 7); - } else { -#if defined(TARGET_MIPS64) - check_insn(ctx, INSN_LOONGSON2E); - gen_loongson_integer(ctx, op1, rd, rs, rt); -#else - /* Invalid in MIPS32 */ - generate_exception(ctx, EXCP_RI); -#endif - } - break; #if defined(TARGET_MIPS64) case OPC_DEXTM ... OPC_DEXT: case OPC_DINSM ... OPC_DINS: @@ -15137,12 +15233,6 @@ static void decode_opc_special3(CPUMIPSState *env, DisasContext *ctx) op2 = MASK_DBSHFL(ctx->opcode); gen_bshfl(ctx, op2, rt, rd); break; - case OPC_DDIV_G_2E ... OPC_DDIVU_G_2E: - case OPC_DMULT_G_2E ... OPC_DMULTU_G_2E: - case OPC_DMODU_G_2E: - check_insn(ctx, INSN_LOONGSON2E); - gen_loongson_integer(ctx, op1, rd, rs, rt); - break; case OPC_ABSQ_S_QH_DSP: op2 = MASK_ABSQ_S_QH(ctx->opcode); switch (op2) { @@ -15374,10 +15464,12 @@ static void decode_opc_special3(CPUMIPSState *env, DisasContext *ctx) gen_mipsdsp_shift(ctx, op1, rd, rs, rt); break; #endif - default: /* Invalid */ - MIPS_INVAL("special3"); - generate_exception(ctx, EXCP_RI); - break; + default: + if (ctx->insn_flags & ISA_MIPS32R6) { + decode_opc_special3_r6(env, ctx); + } else { + decode_opc_special3_legacy(env, ctx); + } } } From fac5a0733013f4e148b406056526f2208464d799 Mon Sep 17 00:00:00 2001 From: Leon Alrae Date: Fri, 27 Jun 2014 08:49:02 +0100 Subject: [PATCH 07/28] target-mips: signal RI Exception on DSP and Loongson instructions Move DSP and Loongson instruction to *_legacy functions as they have been removed in R6. Signed-off-by: Leon Alrae Reviewed-by: Aurelien Jarno --- target-mips/translate.c | 195 ++++++++++++++++++++-------------------- 1 file changed, 98 insertions(+), 97 deletions(-) diff --git a/target-mips/translate.c b/target-mips/translate.c index 0c64aeb87d..11967a0585 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -14783,6 +14783,26 @@ static void decode_opc_special2_legacy(CPUMIPSState *env, DisasContext *ctx) case OPC_MUL: gen_arith(ctx, op1, rd, rs, rt); 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(ctx, INSN_LOONGSON2F); + gen_loongson_integer(ctx, op1, rd, rs, rt); + break; +#if defined(TARGET_MIPS64) + case OPC_DMULT_G_2F: + case OPC_DMULTU_G_2F: + case OPC_DDIV_G_2F: + case OPC_DDIVU_G_2F: + case OPC_DMOD_G_2F: + case OPC_DMODU_G_2F: + check_insn(ctx, INSN_LOONGSON2F); + gen_loongson_integer(ctx, op1, rd, rs, rt); + break; +#endif default: /* Invalid */ MIPS_INVAL("special2_legacy"); generate_exception(ctx, EXCP_RI); @@ -14792,11 +14812,10 @@ static void decode_opc_special2_legacy(CPUMIPSState *env, DisasContext *ctx) static void decode_opc_special2(CPUMIPSState *env, DisasContext *ctx) { - int rs, rt, rd; + int rs, rd; uint32_t op1; rs = (ctx->opcode >> 21) & 0x1f; - rt = (ctx->opcode >> 16) & 0x1f; rd = (ctx->opcode >> 11) & 0x1f; op1 = MASK_SPECIAL2(ctx->opcode); @@ -14818,15 +14837,6 @@ static void decode_opc_special2(CPUMIPSState *env, DisasContext *ctx) } /* Treat as NOP. */ 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(ctx, INSN_LOONGSON2F); - gen_loongson_integer(ctx, op1, rd, rs, rt); - break; #if defined(TARGET_MIPS64) case OPC_DCLO: case OPC_DCLZ: @@ -14834,15 +14844,6 @@ static void decode_opc_special2(CPUMIPSState *env, DisasContext *ctx) 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: - case OPC_DMOD_G_2F: - case OPC_DMODU_G_2F: - check_insn(ctx, INSN_LOONGSON2F); - gen_loongson_integer(ctx, op1, rd, rs, rt); - break; #endif default: if (ctx->insn_flags & ISA_MIPS32R6) { @@ -14880,80 +14881,15 @@ static void decode_opc_special3_r6(CPUMIPSState *env, DisasContext *ctx) static void decode_opc_special3_legacy(CPUMIPSState *env, DisasContext *ctx) { - uint32_t op1; -#if defined(TARGET_MIPS64) - int rd = (ctx->opcode >> 11) & 0x1f; - int rs = (ctx->opcode >> 21) & 0x1f; - int rt = (ctx->opcode >> 16) & 0x1f; -#endif - - op1 = MASK_SPECIAL3(ctx->opcode); - switch (op1) { -#if defined(TARGET_MIPS64) - case OPC_DDIV_G_2E ... OPC_DDIVU_G_2E: - case OPC_DMULT_G_2E ... OPC_DMULTU_G_2E: - case OPC_DMOD_G_2E ... OPC_DMODU_G_2E: - check_insn(ctx, INSN_LOONGSON2E); - gen_loongson_integer(ctx, op1, rd, rs, rt); - break; -#endif - default: /* Invalid */ - MIPS_INVAL("special3_legacy"); - generate_exception(ctx, EXCP_RI); - break; - } -} - -static void decode_opc_special3(CPUMIPSState *env, DisasContext *ctx) -{ - int rs, rt, rd, sa; + int rs, rt, rd; uint32_t op1, op2; rs = (ctx->opcode >> 21) & 0x1f; rt = (ctx->opcode >> 16) & 0x1f; rd = (ctx->opcode >> 11) & 0x1f; - sa = (ctx->opcode >> 6) & 0x1f; op1 = MASK_SPECIAL3(ctx->opcode); switch (op1) { - case OPC_EXT: - case OPC_INS: - check_insn(ctx, ISA_MIPS32R2); - gen_bitops(ctx, op1, rt, rs, sa, rd); - break; - case OPC_BSHFL: - check_insn(ctx, ISA_MIPS32R2); - op2 = MASK_BSHFL(ctx->opcode); - gen_bshfl(ctx, op2, rt, rd); - break; - case OPC_RDHWR: - gen_rdhwr(ctx, rt, rd); - break; - case OPC_FORK: - check_insn(ctx, ASE_MT); - { - TCGv t0 = tcg_temp_new(); - TCGv t1 = tcg_temp_new(); - - gen_load_gpr(t0, rt); - gen_load_gpr(t1, rs); - gen_helper_fork(t0, t1); - tcg_temp_free(t0); - tcg_temp_free(t1); - } - break; - case OPC_YIELD: - check_insn(ctx, ASE_MT); - { - TCGv t0 = tcg_temp_new(); - - save_cpu_state(ctx, 1); - gen_load_gpr(t0, rs); - gen_helper_yield(t0, cpu_env, t0); - gen_store_gpr(t0, rd); - tcg_temp_free(t0); - } - break; case OPC_DIV_G_2E ... OPC_DIVU_G_2E: case OPC_MOD_G_2E ... OPC_MODU_G_2E: case OPC_MULT_G_2E ... OPC_MULTU_G_2E: @@ -15221,17 +15157,11 @@ static void decode_opc_special3(CPUMIPSState *env, DisasContext *ctx) } break; #if defined(TARGET_MIPS64) - case OPC_DEXTM ... OPC_DEXT: - case OPC_DINSM ... OPC_DINS: - check_insn(ctx, ISA_MIPS64R2); - check_mips_64(ctx); - gen_bitops(ctx, op1, rt, rs, sa, rd); - break; - case OPC_DBSHFL: - check_insn(ctx, ISA_MIPS64R2); - check_mips_64(ctx); - op2 = MASK_DBSHFL(ctx->opcode); - gen_bshfl(ctx, op2, rt, rd); + case OPC_DDIV_G_2E ... OPC_DDIVU_G_2E: + case OPC_DMULT_G_2E ... OPC_DMULTU_G_2E: + case OPC_DMOD_G_2E ... OPC_DMODU_G_2E: + check_insn(ctx, INSN_LOONGSON2E); + gen_loongson_integer(ctx, op1, rd, rs, rt); break; case OPC_ABSQ_S_QH_DSP: op2 = MASK_ABSQ_S_QH(ctx->opcode); @@ -15464,6 +15394,77 @@ static void decode_opc_special3(CPUMIPSState *env, DisasContext *ctx) gen_mipsdsp_shift(ctx, op1, rd, rs, rt); break; #endif + default: /* Invalid */ + MIPS_INVAL("special3_legacy"); + generate_exception(ctx, EXCP_RI); + break; + } +} + +static void decode_opc_special3(CPUMIPSState *env, DisasContext *ctx) +{ + int rs, rt, rd, sa; + uint32_t op1, op2; + + rs = (ctx->opcode >> 21) & 0x1f; + rt = (ctx->opcode >> 16) & 0x1f; + rd = (ctx->opcode >> 11) & 0x1f; + sa = (ctx->opcode >> 6) & 0x1f; + + op1 = MASK_SPECIAL3(ctx->opcode); + switch (op1) { + case OPC_EXT: + case OPC_INS: + check_insn(ctx, ISA_MIPS32R2); + gen_bitops(ctx, op1, rt, rs, sa, rd); + break; + case OPC_BSHFL: + check_insn(ctx, ISA_MIPS32R2); + op2 = MASK_BSHFL(ctx->opcode); + gen_bshfl(ctx, op2, rt, rd); + break; +#if defined(TARGET_MIPS64) + case OPC_DEXTM ... OPC_DEXT: + case OPC_DINSM ... OPC_DINS: + check_insn(ctx, ISA_MIPS64R2); + check_mips_64(ctx); + gen_bitops(ctx, op1, rt, rs, sa, rd); + break; + case OPC_DBSHFL: + check_insn(ctx, ISA_MIPS64R2); + check_mips_64(ctx); + op2 = MASK_DBSHFL(ctx->opcode); + gen_bshfl(ctx, op2, rt, rd); + break; +#endif + case OPC_RDHWR: + gen_rdhwr(ctx, rt, rd); + break; + case OPC_FORK: + check_insn(ctx, ASE_MT); + { + TCGv t0 = tcg_temp_new(); + TCGv t1 = tcg_temp_new(); + + gen_load_gpr(t0, rt); + gen_load_gpr(t1, rs); + gen_helper_fork(t0, t1); + tcg_temp_free(t0); + tcg_temp_free(t1); + } + break; + case OPC_YIELD: + check_insn(ctx, ASE_MT); + { + TCGv t0 = tcg_temp_new(); + + save_cpu_state(ctx, 1); + gen_load_gpr(t0, rs); + gen_helper_yield(t0, cpu_env, t0); + gen_store_gpr(t0, rd); + tcg_temp_free(t0); + } + break; default: if (ctx->insn_flags & ISA_MIPS32R6) { decode_opc_special3_r6(env, ctx); From bf7910c6b1bc47517a9d7a6049d97d056e014eb0 Mon Sep 17 00:00:00 2001 From: Leon Alrae Date: Fri, 27 Jun 2014 08:49:03 +0100 Subject: [PATCH 08/28] target-mips: move PREF, CACHE, LLD and SCD instructions The encoding of PREF, CACHE, LLD and SCD instruction changed in MIPS32R6. Additionally, the hint codes in PREF instruction greater than or equal to 24 generate Reserved Instruction Exception. Signed-off-by: Leon Alrae Reviewed-by: Aurelien Jarno --- disas/mips.c | 4 ++++ target-mips/translate.c | 29 ++++++++++++++++++++++++++++- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/disas/mips.c b/disas/mips.c index f0efa8b29c..cae76ed482 100644 --- a/disas/mips.c +++ b/disas/mips.c @@ -1219,6 +1219,10 @@ const struct mips_opcode mips_builtin_opcodes[] = /* name, args, match, mask, pinfo, membership */ {"ll", "t,o(b)", 0x7c000036, 0xfc00007f, LDD|RD_b|WR_t, 0, I32R6}, {"sc", "t,o(b)", 0x7c000026, 0xfc00007f, LDD|RD_b|WR_t, 0, I32R6}, +{"lld", "t,o(b)", 0x7c000037, 0xfc00007f, LDD|RD_b|WR_t, 0, I64R6}, +{"scd", "t,o(b)", 0x7c000027, 0xfc00007f, LDD|RD_b|WR_t, 0, I64R6}, +{"pref", "h,o(b)", 0x7c000035, 0xfc00007f, RD_b, 0, I32R6}, +{"cache", "k,o(b)", 0x7c000025, 0xfc00007f, RD_b, 0, I32R6}, {"seleqz", "d,v,t", 0x00000035, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I32R6}, {"selnez", "d,v,t", 0x00000037, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I32R6}, {"pref", "k,o(b)", 0xcc000000, 0xfc000000, RD_b, 0, I4|I32|G3 }, diff --git a/target-mips/translate.c b/target-mips/translate.c index 11967a0585..f50d906cc1 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -349,8 +349,12 @@ enum { OPC_DEXTR_W_DSP = 0x3C | OPC_SPECIAL3, /* R6 */ + R6_OPC_PREF = 0x35 | OPC_SPECIAL3, + R6_OPC_CACHE = 0x25 | OPC_SPECIAL3, R6_OPC_LL = 0x36 | OPC_SPECIAL3, R6_OPC_SC = 0x26 | OPC_SPECIAL3, + R6_OPC_LLD = 0x37 | OPC_SPECIAL3, + R6_OPC_SCD = 0x27 | OPC_SPECIAL3, }; /* BSHFL opcodes */ @@ -1645,6 +1649,7 @@ static void gen_ld(DisasContext *ctx, uint32_t opc, opn = "ld"; break; case OPC_LLD: + case R6_OPC_LLD: save_cpu_state(ctx, 1); op_ld_lld(t0, t0, ctx); gen_store_gpr(t0, rt); @@ -1867,6 +1872,7 @@ static void gen_st_cond (DisasContext *ctx, uint32_t opc, int rt, switch (opc) { #if defined(TARGET_MIPS64) case OPC_SCD: + case R6_OPC_SCD: save_cpu_state(ctx, 1); op_st_scd(t1, t0, rt, ctx); opn = "scd"; @@ -14866,12 +14872,30 @@ static void decode_opc_special3_r6(CPUMIPSState *env, DisasContext *ctx) op1 = MASK_SPECIAL3(ctx->opcode); switch (op1) { + case R6_OPC_PREF: + if (rt >= 24) { + /* hint codes 24-31 are reserved and signal RI */ + generate_exception(ctx, EXCP_RI); + } + /* Treat as NOP. */ + break; + case R6_OPC_CACHE: + /* Treat as NOP. */ + break; case R6_OPC_SC: gen_st_cond(ctx, op1, rt, rs, imm); break; case R6_OPC_LL: gen_ld(ctx, op1, rt, rs, imm); break; +#if defined(TARGET_MIPS64) + case R6_OPC_SCD: + gen_st_cond(ctx, op1, rt, rs, imm); + break; + case R6_OPC_LLD: + gen_ld(ctx, op1, rt, rs, imm); + break; +#endif default: /* Invalid */ MIPS_INVAL("special3_r6"); generate_exception(ctx, EXCP_RI); @@ -15686,11 +15710,13 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx) gen_st_cond(ctx, op, rt, rs, imm); break; case OPC_CACHE: + check_insn_opc_removed(ctx, ISA_MIPS32R6); check_cp0_enabled(ctx); check_insn(ctx, ISA_MIPS3 | ISA_MIPS32); /* Treat as NOP. */ break; case OPC_PREF: + check_insn_opc_removed(ctx, ISA_MIPS32R6); check_insn(ctx, ISA_MIPS4 | ISA_MIPS32); /* Treat as NOP. */ break; @@ -15813,9 +15839,9 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx) #if defined(TARGET_MIPS64) /* MIPS64 opcodes */ case OPC_LDL ... OPC_LDR: + case OPC_LLD: check_insn_opc_removed(ctx, ISA_MIPS32R6); case OPC_LWU: - case OPC_LLD: case OPC_LD: check_insn(ctx, ISA_MIPS3); check_mips_64(ctx); @@ -15829,6 +15855,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx) gen_st(ctx, op, rt, rs, imm); break; case OPC_SCD: + check_insn_opc_removed(ctx, ISA_MIPS32R6); check_insn(ctx, ISA_MIPS3); check_mips_64(ctx); gen_st_cond(ctx, op, rt, rs, imm); From b42ee5e1d97c035b832f9b5c8e0decd286ec091c Mon Sep 17 00:00:00 2001 From: Leon Alrae Date: Fri, 27 Jun 2014 08:49:03 +0100 Subject: [PATCH 09/28] target-mips: redefine Integer Multiply and Divide instructions Use "R6_" prefix in front of all new Multiply / Divide instructions for easier differentiation between R6 and preR6. Signed-off-by: Leon Alrae Reviewed-by: Aurelien Jarno --- disas/mips.c | 16 ++ target-mips/translate.c | 343 +++++++++++++++++++++++++++++++++++++--- 2 files changed, 338 insertions(+), 21 deletions(-) diff --git a/disas/mips.c b/disas/mips.c index cae76ed482..16cb2acd81 100644 --- a/disas/mips.c +++ b/disas/mips.c @@ -1217,6 +1217,22 @@ const struct mips_opcode mips_builtin_opcodes[] = them first. The assemblers uses a hash table based on the instruction name anyhow. */ /* name, args, match, mask, pinfo, membership */ +{"mul", "d,s,t", 0x00000098, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I32R6}, +{"muh", "d,s,t", 0x000000d8, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I32R6}, +{"mulu", "d,s,t", 0x00000099, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I32R6}, +{"muhu", "d,s,t", 0x000000d9, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I32R6}, +{"div", "d,s,t", 0x0000009a, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I32R6}, +{"mod", "d,s,t", 0x000000da, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I32R6}, +{"divu", "d,s,t", 0x0000009b, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I32R6}, +{"modu", "d,s,t", 0x000000db, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I32R6}, +{"dmul", "d,s,t", 0x0000009c, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I64R6}, +{"dmuh", "d,s,t", 0x000000dc, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I64R6}, +{"dmulu", "d,s,t", 0x0000009d, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I64R6}, +{"dmuhu", "d,s,t", 0x000000dd, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I64R6}, +{"ddiv", "d,s,t", 0x0000009e, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I64R6}, +{"dmod", "d,s,t", 0x000000de, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I64R6}, +{"ddivu", "d,s,t", 0x0000009f, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I64R6}, +{"dmodu", "d,s,t", 0x000000df, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I64R6}, {"ll", "t,o(b)", 0x7c000036, 0xfc00007f, LDD|RD_b|WR_t, 0, I32R6}, {"sc", "t,o(b)", 0x7c000026, 0xfc00007f, LDD|RD_b|WR_t, 0, I32R6}, {"lld", "t,o(b)", 0x7c000037, 0xfc00007f, LDD|RD_b|WR_t, 0, I64R6}, diff --git a/target-mips/translate.c b/target-mips/translate.c index f50d906cc1..3ce9641fd9 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -157,6 +157,7 @@ enum { OPC_DMULTU = 0x1D | OPC_SPECIAL, OPC_DDIV = 0x1E | OPC_SPECIAL, OPC_DDIVU = 0x1F | OPC_SPECIAL, + /* 2 registers arithmetic / logic */ OPC_ADD = 0x20 | OPC_SPECIAL, OPC_ADDU = 0x21 | OPC_SPECIAL, @@ -212,6 +213,30 @@ enum { OPC_SPECIAL3D_RESERVED = 0x3D | OPC_SPECIAL, }; +/* R6 Multiply and Divide instructions have the same Opcode + and function field as legacy OPC_MULT[U]/OPC_DIV[U] */ +#define MASK_R6_MULDIV(op) (MASK_SPECIAL(op) | (op & (0x7ff))) + +enum { + R6_OPC_MUL = OPC_MULT | (2 << 6), + R6_OPC_MUH = OPC_MULT | (3 << 6), + R6_OPC_MULU = OPC_MULTU | (2 << 6), + R6_OPC_MUHU = OPC_MULTU | (3 << 6), + R6_OPC_DIV = OPC_DIV | (2 << 6), + R6_OPC_MOD = OPC_DIV | (3 << 6), + R6_OPC_DIVU = OPC_DIVU | (2 << 6), + R6_OPC_MODU = OPC_DIVU | (3 << 6), + + R6_OPC_DMUL = OPC_DMULT | (2 << 6), + R6_OPC_DMUH = OPC_DMULT | (3 << 6), + R6_OPC_DMULU = OPC_DMULTU | (2 << 6), + R6_OPC_DMUHU = OPC_DMULTU | (3 << 6), + R6_OPC_DDIV = OPC_DDIV | (2 << 6), + R6_OPC_DMOD = OPC_DDIV | (3 << 6), + R6_OPC_DDIVU = OPC_DDIVU | (2 << 6), + R6_OPC_DMODU = OPC_DDIVU | (3 << 6), +}; + /* Multiplication variants of the vr54xx. */ #define MASK_MUL_VR54XX(op) MASK_SPECIAL(op) | (op & (0x1F << 6)) @@ -2691,6 +2716,238 @@ static void gen_HILO(DisasContext *ctx, uint32_t opc, int acc, int reg) MIPS_DEBUG("%s %s", opn, regnames[reg]); } +static void gen_r6_muldiv(DisasContext *ctx, int opc, int rd, int rs, int rt) +{ + const char *opn = "r6 mul/div"; + TCGv t0, t1; + + if (rd == 0) { + /* Treat as NOP. */ + MIPS_DEBUG("NOP"); + return; + } + + t0 = tcg_temp_new(); + t1 = tcg_temp_new(); + + gen_load_gpr(t0, rs); + gen_load_gpr(t1, rt); + + switch (opc) { + case R6_OPC_DIV: + { + TCGv t2 = tcg_temp_new(); + TCGv t3 = tcg_temp_new(); + tcg_gen_ext32s_tl(t0, t0); + tcg_gen_ext32s_tl(t1, t1); + tcg_gen_setcondi_tl(TCG_COND_EQ, t2, t0, INT_MIN); + tcg_gen_setcondi_tl(TCG_COND_EQ, t3, t1, -1); + tcg_gen_and_tl(t2, t2, t3); + tcg_gen_setcondi_tl(TCG_COND_EQ, t3, t1, 0); + tcg_gen_or_tl(t2, t2, t3); + tcg_gen_movi_tl(t3, 0); + tcg_gen_movcond_tl(TCG_COND_NE, t1, t2, t3, t2, t1); + tcg_gen_div_tl(cpu_gpr[rd], t0, t1); + tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]); + tcg_temp_free(t3); + tcg_temp_free(t2); + } + opn = "div"; + break; + case R6_OPC_MOD: + { + TCGv t2 = tcg_temp_new(); + TCGv t3 = tcg_temp_new(); + tcg_gen_ext32s_tl(t0, t0); + tcg_gen_ext32s_tl(t1, t1); + tcg_gen_setcondi_tl(TCG_COND_EQ, t2, t0, INT_MIN); + tcg_gen_setcondi_tl(TCG_COND_EQ, t3, t1, -1); + tcg_gen_and_tl(t2, t2, t3); + tcg_gen_setcondi_tl(TCG_COND_EQ, t3, t1, 0); + tcg_gen_or_tl(t2, t2, t3); + tcg_gen_movi_tl(t3, 0); + tcg_gen_movcond_tl(TCG_COND_NE, t1, t2, t3, t2, t1); + tcg_gen_rem_tl(cpu_gpr[rd], t0, t1); + tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]); + tcg_temp_free(t3); + tcg_temp_free(t2); + } + opn = "mod"; + break; + case R6_OPC_DIVU: + { + TCGv t2 = tcg_const_tl(0); + TCGv t3 = tcg_const_tl(1); + tcg_gen_ext32u_tl(t0, t0); + tcg_gen_ext32u_tl(t1, t1); + tcg_gen_movcond_tl(TCG_COND_EQ, t1, t1, t2, t3, t1); + tcg_gen_divu_tl(cpu_gpr[rd], t0, t1); + tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]); + tcg_temp_free(t3); + tcg_temp_free(t2); + } + opn = "divu"; + break; + case R6_OPC_MODU: + { + TCGv t2 = tcg_const_tl(0); + TCGv t3 = tcg_const_tl(1); + tcg_gen_ext32u_tl(t0, t0); + tcg_gen_ext32u_tl(t1, t1); + tcg_gen_movcond_tl(TCG_COND_EQ, t1, t1, t2, t3, t1); + tcg_gen_remu_tl(cpu_gpr[rd], t0, t1); + tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]); + tcg_temp_free(t3); + tcg_temp_free(t2); + } + opn = "modu"; + break; + case R6_OPC_MUL: + { + TCGv_i32 t2 = tcg_temp_new_i32(); + TCGv_i32 t3 = tcg_temp_new_i32(); + tcg_gen_trunc_tl_i32(t2, t0); + tcg_gen_trunc_tl_i32(t3, t1); + tcg_gen_mul_i32(t2, t2, t3); + tcg_gen_ext_i32_tl(cpu_gpr[rd], t2); + tcg_temp_free_i32(t2); + tcg_temp_free_i32(t3); + } + opn = "mul"; + break; + case R6_OPC_MUH: + { + TCGv_i32 t2 = tcg_temp_new_i32(); + TCGv_i32 t3 = tcg_temp_new_i32(); + tcg_gen_trunc_tl_i32(t2, t0); + tcg_gen_trunc_tl_i32(t3, t1); + tcg_gen_muls2_i32(t2, t3, t2, t3); + tcg_gen_ext_i32_tl(cpu_gpr[rd], t3); + tcg_temp_free_i32(t2); + tcg_temp_free_i32(t3); + } + opn = "muh"; + break; + case R6_OPC_MULU: + { + TCGv_i32 t2 = tcg_temp_new_i32(); + TCGv_i32 t3 = tcg_temp_new_i32(); + tcg_gen_trunc_tl_i32(t2, t0); + tcg_gen_trunc_tl_i32(t3, t1); + tcg_gen_mul_i32(t2, t2, t3); + tcg_gen_ext_i32_tl(cpu_gpr[rd], t2); + tcg_temp_free_i32(t2); + tcg_temp_free_i32(t3); + } + opn = "mulu"; + break; + case R6_OPC_MUHU: + { + TCGv_i32 t2 = tcg_temp_new_i32(); + TCGv_i32 t3 = tcg_temp_new_i32(); + tcg_gen_trunc_tl_i32(t2, t0); + tcg_gen_trunc_tl_i32(t3, t1); + tcg_gen_mulu2_i32(t2, t3, t2, t3); + tcg_gen_ext_i32_tl(cpu_gpr[rd], t3); + tcg_temp_free_i32(t2); + tcg_temp_free_i32(t3); + } + opn = "muhu"; + break; +#if defined(TARGET_MIPS64) + case R6_OPC_DDIV: + { + TCGv t2 = tcg_temp_new(); + TCGv t3 = tcg_temp_new(); + tcg_gen_setcondi_tl(TCG_COND_EQ, t2, t0, -1LL << 63); + tcg_gen_setcondi_tl(TCG_COND_EQ, t3, t1, -1LL); + tcg_gen_and_tl(t2, t2, t3); + tcg_gen_setcondi_tl(TCG_COND_EQ, t3, t1, 0); + tcg_gen_or_tl(t2, t2, t3); + tcg_gen_movi_tl(t3, 0); + tcg_gen_movcond_tl(TCG_COND_NE, t1, t2, t3, t2, t1); + tcg_gen_div_tl(cpu_gpr[rd], t0, t1); + tcg_temp_free(t3); + tcg_temp_free(t2); + } + opn = "ddiv"; + break; + case R6_OPC_DMOD: + { + TCGv t2 = tcg_temp_new(); + TCGv t3 = tcg_temp_new(); + tcg_gen_setcondi_tl(TCG_COND_EQ, t2, t0, -1LL << 63); + tcg_gen_setcondi_tl(TCG_COND_EQ, t3, t1, -1LL); + tcg_gen_and_tl(t2, t2, t3); + tcg_gen_setcondi_tl(TCG_COND_EQ, t3, t1, 0); + tcg_gen_or_tl(t2, t2, t3); + tcg_gen_movi_tl(t3, 0); + tcg_gen_movcond_tl(TCG_COND_NE, t1, t2, t3, t2, t1); + tcg_gen_rem_tl(cpu_gpr[rd], t0, t1); + tcg_temp_free(t3); + tcg_temp_free(t2); + } + opn = "dmod"; + break; + case R6_OPC_DDIVU: + { + TCGv t2 = tcg_const_tl(0); + TCGv t3 = tcg_const_tl(1); + tcg_gen_movcond_tl(TCG_COND_EQ, t1, t1, t2, t3, t1); + tcg_gen_divu_i64(cpu_gpr[rd], t0, t1); + tcg_temp_free(t3); + tcg_temp_free(t2); + } + opn = "ddivu"; + break; + case R6_OPC_DMODU: + { + TCGv t2 = tcg_const_tl(0); + TCGv t3 = tcg_const_tl(1); + tcg_gen_movcond_tl(TCG_COND_EQ, t1, t1, t2, t3, t1); + tcg_gen_remu_i64(cpu_gpr[rd], t0, t1); + tcg_temp_free(t3); + tcg_temp_free(t2); + } + opn = "dmodu"; + break; + case R6_OPC_DMUL: + tcg_gen_mul_i64(cpu_gpr[rd], t0, t1); + opn = "dmul"; + break; + case R6_OPC_DMUH: + { + TCGv t2 = tcg_temp_new(); + tcg_gen_muls2_i64(t2, cpu_gpr[rd], t0, t1); + tcg_temp_free(t2); + } + opn = "dmuh"; + break; + case R6_OPC_DMULU: + tcg_gen_mul_i64(cpu_gpr[rd], t0, t1); + opn = "dmulu"; + break; + case R6_OPC_DMUHU: + { + TCGv t2 = tcg_temp_new(); + tcg_gen_mulu2_i64(t2, cpu_gpr[rd], t0, t1); + tcg_temp_free(t2); + } + opn = "dmuhu"; + break; +#endif + default: + MIPS_INVAL(opn); + generate_exception(ctx, EXCP_RI); + goto out; + } + (void)opn; /* avoid a compiler warning */ + MIPS_DEBUG("%s %s %s", opn, regnames[rs], regnames[rt]); + out: + tcg_temp_free(t0); + tcg_temp_free(t1); +} + static void gen_muldiv(DisasContext *ctx, uint32_t opc, int acc, int rs, int rt) { @@ -14491,7 +14748,7 @@ static void gen_mipsdsp_accinsn(DisasContext *ctx, uint32_t op1, uint32_t op2, static void decode_opc_special_r6(CPUMIPSState *env, DisasContext *ctx) { int rs, rt, rd; - uint32_t op1; + uint32_t op1, op2; rs = (ctx->opcode >> 21) & 0x1f; rt = (ctx->opcode >> 16) & 0x1f; @@ -14499,10 +14756,51 @@ static void decode_opc_special_r6(CPUMIPSState *env, DisasContext *ctx) op1 = MASK_SPECIAL(ctx->opcode); switch (op1) { + case OPC_MULT ... OPC_DIVU: + op2 = MASK_R6_MULDIV(ctx->opcode); + switch (op2) { + case R6_OPC_MUL: + case R6_OPC_MUH: + case R6_OPC_MULU: + case R6_OPC_MUHU: + case R6_OPC_DIV: + case R6_OPC_MOD: + case R6_OPC_DIVU: + case R6_OPC_MODU: + gen_r6_muldiv(ctx, op2, rd, rs, rt); + break; + default: + MIPS_INVAL("special_r6 muldiv"); + generate_exception(ctx, EXCP_RI); + break; + } + break; case OPC_SELEQZ: case OPC_SELNEZ: gen_cond_move(ctx, op1, rd, rs, rt); break; +#if defined(TARGET_MIPS64) + case OPC_DMULT ... OPC_DDIVU: + op2 = MASK_R6_MULDIV(ctx->opcode); + switch (op2) { + case R6_OPC_DMUL: + case R6_OPC_DMUH: + case R6_OPC_DMULU: + case R6_OPC_DMUHU: + case R6_OPC_DDIV: + case R6_OPC_DMOD: + case R6_OPC_DDIVU: + case R6_OPC_DMODU: + check_mips_64(ctx); + gen_r6_muldiv(ctx, op2, rd, rs, rt); + break; + default: + MIPS_INVAL("special_r6 muldiv"); + generate_exception(ctx, EXCP_RI); + break; + } + break; +#endif default: /* Invalid */ MIPS_INVAL("special_r6"); generate_exception(ctx, EXCP_RI); @@ -14512,12 +14810,13 @@ static void decode_opc_special_r6(CPUMIPSState *env, DisasContext *ctx) static void decode_opc_special_legacy(CPUMIPSState *env, DisasContext *ctx) { - int rs, rt, rd; + int rs, rt, rd, sa; uint32_t op1; rs = (ctx->opcode >> 21) & 0x1f; rt = (ctx->opcode >> 16) & 0x1f; rd = (ctx->opcode >> 11) & 0x1f; + sa = (ctx->opcode >> 6) & 0x1f; op1 = MASK_SPECIAL(ctx->opcode); switch (op1) { @@ -14545,6 +14844,27 @@ static void decode_opc_special_legacy(CPUMIPSState *env, DisasContext *ctx) generate_exception_err(ctx, EXCP_CpU, 1); } break; + case OPC_MULT: + case OPC_MULTU: + if (sa) { + check_insn(ctx, INSN_VR54XX); + op1 = MASK_MUL_VR54XX(ctx->opcode); + gen_mul_vr54xx(ctx, op1, rd, rs, rt); + } else { + gen_muldiv(ctx, op1, rd & 3, rs, rt); + } + break; + case OPC_DIV: + case OPC_DIVU: + gen_muldiv(ctx, op1, 0, rs, rt); + break; +#if defined(TARGET_MIPS64) + case OPC_DMULT ... OPC_DDIVU: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); + gen_muldiv(ctx, op1, 0, rs, rt); + break; +#endif default: /* Invalid */ MIPS_INVAL("special_legacy"); generate_exception(ctx, EXCP_RI); @@ -14617,20 +14937,6 @@ static void decode_opc_special(CPUMIPSState *env, DisasContext *ctx) case OPC_XOR: gen_logic(ctx, op1, rd, rs, rt); break; - case OPC_MULT: - case OPC_MULTU: - if (sa) { - check_insn(ctx, INSN_VR54XX); - op1 = MASK_MUL_VR54XX(ctx->opcode); - gen_mul_vr54xx(ctx, op1, rd, rs, rt); - } else { - gen_muldiv(ctx, op1, rd & 3, rs, rt); - } - break; - case OPC_DIV: - case OPC_DIVU: - gen_muldiv(ctx, op1, 0, rs, rt); - break; case OPC_JR ... OPC_JALR: gen_compute_branch(ctx, op1, 4, rs, rd, sa); break; @@ -14742,11 +15048,6 @@ static void decode_opc_special(CPUMIPSState *env, DisasContext *ctx) break; } break; - case OPC_DMULT ... OPC_DDIVU: - check_insn(ctx, ISA_MIPS3); - check_mips_64(ctx); - gen_muldiv(ctx, op1, 0, rs, rt); - break; #endif default: if (ctx->insn_flags & ISA_MIPS32R6) { From 4267d3e6e0d7be184ef343919640e7be6ae34e71 Mon Sep 17 00:00:00 2001 From: Leon Alrae Date: Fri, 27 Jun 2014 08:49:04 +0100 Subject: [PATCH 10/28] target-mips: move CLO, DCLO, CLZ, DCLZ, SDBBP and free special2 in R6 Also consider OPC_SPIM instruction as deleted in R6 because it is overlaping with MIPS32R6 SDBBP. Signed-off-by: Leon Alrae Reviewed-by: Aurelien Jarno --- disas/mips.c | 5 ++ target-mips/translate.c | 121 ++++++++++++++++++++-------------------- 2 files changed, 67 insertions(+), 59 deletions(-) diff --git a/disas/mips.c b/disas/mips.c index 16cb2acd81..8ee8758e50 100644 --- a/disas/mips.c +++ b/disas/mips.c @@ -1217,6 +1217,11 @@ const struct mips_opcode mips_builtin_opcodes[] = them first. The assemblers uses a hash table based on the instruction name anyhow. */ /* name, args, match, mask, pinfo, membership */ +{"clz", "U,s", 0x00000050, 0xfc1f07ff, WR_d|RD_s, 0, I32R6}, +{"clo", "U,s", 0x00000051, 0xfc1f07ff, WR_d|RD_s, 0, I32R6}, +{"dclz", "U,s", 0x00000052, 0xfc1f07ff, WR_d|RD_s, 0, I64R6}, +{"dclo", "U,s", 0x00000053, 0xfc1f07ff, WR_d|RD_s, 0, I64R6}, +{"sdbbp", "B", 0x0000000e, 0xfc00003f, TRAP, 0, I32R6}, {"mul", "d,s,t", 0x00000098, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I32R6}, {"muh", "d,s,t", 0x000000d8, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I32R6}, {"mulu", "d,s,t", 0x00000099, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I32R6}, diff --git a/target-mips/translate.c b/target-mips/translate.c index 3ce9641fd9..34d63ea215 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -235,6 +235,12 @@ enum { R6_OPC_DMOD = OPC_DDIV | (3 << 6), R6_OPC_DDIVU = OPC_DDIVU | (2 << 6), R6_OPC_DMODU = OPC_DDIVU | (3 << 6), + + R6_OPC_CLZ = 0x10 | OPC_SPECIAL, + R6_OPC_CLO = 0x11 | OPC_SPECIAL, + R6_OPC_DCLZ = 0x12 | OPC_SPECIAL, + R6_OPC_DCLO = 0x13 | OPC_SPECIAL, + R6_OPC_SDBBP = 0x0e | OPC_SPECIAL, }; /* Multiplication variants of the vr54xx. */ @@ -3263,19 +3269,23 @@ static void gen_cl (DisasContext *ctx, uint32_t opc, gen_load_gpr(t0, rs); switch (opc) { case OPC_CLO: + case R6_OPC_CLO: gen_helper_clo(cpu_gpr[rd], t0); opn = "clo"; break; case OPC_CLZ: + case R6_OPC_CLZ: gen_helper_clz(cpu_gpr[rd], t0); opn = "clz"; break; #if defined(TARGET_MIPS64) case OPC_DCLO: + case R6_OPC_DCLO: gen_helper_dclo(cpu_gpr[rd], t0); opn = "dclo"; break; case OPC_DCLZ: + case R6_OPC_DCLZ: gen_helper_dclz(cpu_gpr[rd], t0); opn = "dclz"; break; @@ -14747,12 +14757,13 @@ static void gen_mipsdsp_accinsn(DisasContext *ctx, uint32_t op1, uint32_t op2, static void decode_opc_special_r6(CPUMIPSState *env, DisasContext *ctx) { - int rs, rt, rd; + int rs, rt, rd, sa; uint32_t op1, op2; rs = (ctx->opcode >> 21) & 0x1f; rt = (ctx->opcode >> 16) & 0x1f; rd = (ctx->opcode >> 11) & 0x1f; + sa = (ctx->opcode >> 6) & 0x1f; op1 = MASK_SPECIAL(ctx->opcode); switch (op1) { @@ -14779,7 +14790,31 @@ static void decode_opc_special_r6(CPUMIPSState *env, DisasContext *ctx) case OPC_SELNEZ: gen_cond_move(ctx, op1, rd, rs, rt); break; + case R6_OPC_CLO: + case R6_OPC_CLZ: + if (rt == 0 && sa == 1) { + /* Major opcode and function field is shared with preR6 MFHI/MTHI. + We need additionally to check other fields */ + gen_cl(ctx, op1, rd, rs); + } else { + generate_exception(ctx, EXCP_RI); + } + break; + case R6_OPC_SDBBP: + generate_exception(ctx, EXCP_DBp); + break; #if defined(TARGET_MIPS64) + case R6_OPC_DCLO: + case R6_OPC_DCLZ: + if (rt == 0 && sa == 1) { + /* Major opcode and function field is shared with preR6 MFHI/MTHI. + We need additionally to check other fields */ + check_mips_64(ctx); + gen_cl(ctx, op1, rd, rs); + } else { + generate_exception(ctx, EXCP_RI); + } + break; case OPC_DMULT ... OPC_DDIVU: op2 = MASK_R6_MULDIV(ctx->opcode); switch (op2) { @@ -14865,6 +14900,16 @@ static void decode_opc_special_legacy(CPUMIPSState *env, DisasContext *ctx) gen_muldiv(ctx, op1, 0, rs, rt); break; #endif + case OPC_SPIM: +#ifdef MIPS_STRICT_STANDARD + MIPS_INVAL("SPIM"); + generate_exception(ctx, EXCP_RI); +#else + /* Implemented as RI exception for now. */ + MIPS_INVAL("spim (unofficial)"); + generate_exception(ctx, EXCP_RI); +#endif + break; default: /* Invalid */ MIPS_INVAL("special_legacy"); generate_exception(ctx, EXCP_RI); @@ -14959,16 +15004,6 @@ static void decode_opc_special(CPUMIPSState *env, DisasContext *ctx) case OPC_BREAK: generate_exception(ctx, EXCP_BREAK); break; - case OPC_SPIM: -#ifdef MIPS_STRICT_STANDARD - MIPS_INVAL("SPIM"); - generate_exception(ctx, EXCP_RI); -#else - /* Implemented as RI exception for now. */ - MIPS_INVAL("spim (unofficial)"); - generate_exception(ctx, EXCP_RI); -#endif - break; case OPC_SYNC: /* Treat as NOP. */ break; @@ -15058,24 +15093,13 @@ static void decode_opc_special(CPUMIPSState *env, DisasContext *ctx) } } -static void decode_opc_special2_r6(CPUMIPSState *env, DisasContext *ctx) -{ - uint32_t op1; - - op1 = MASK_SPECIAL2(ctx->opcode); - switch (op1) { - default: /* Invalid */ - MIPS_INVAL("special2_r6"); - generate_exception(ctx, EXCP_RI); - break; - } -} - static void decode_opc_special2_legacy(CPUMIPSState *env, DisasContext *ctx) { int rs, rt, rd; uint32_t op1; + check_insn_opc_removed(ctx, ISA_MIPS32R6); + rs = (ctx->opcode >> 21) & 0x1f; rt = (ctx->opcode >> 16) & 0x1f; rd = (ctx->opcode >> 11) & 0x1f; @@ -15099,34 +15123,6 @@ static void decode_opc_special2_legacy(CPUMIPSState *env, DisasContext *ctx) check_insn(ctx, INSN_LOONGSON2F); gen_loongson_integer(ctx, op1, rd, rs, rt); break; -#if defined(TARGET_MIPS64) - case OPC_DMULT_G_2F: - case OPC_DMULTU_G_2F: - case OPC_DDIV_G_2F: - case OPC_DDIVU_G_2F: - case OPC_DMOD_G_2F: - case OPC_DMODU_G_2F: - check_insn(ctx, INSN_LOONGSON2F); - gen_loongson_integer(ctx, op1, rd, rs, rt); - break; -#endif - default: /* Invalid */ - MIPS_INVAL("special2_legacy"); - generate_exception(ctx, EXCP_RI); - break; - } -} - -static void decode_opc_special2(CPUMIPSState *env, DisasContext *ctx) -{ - int rs, rd; - uint32_t op1; - - rs = (ctx->opcode >> 21) & 0x1f; - rd = (ctx->opcode >> 11) & 0x1f; - - op1 = MASK_SPECIAL2(ctx->opcode); - switch (op1) { case OPC_CLO: case OPC_CLZ: check_insn(ctx, ISA_MIPS32); @@ -15151,13 +15147,20 @@ static void decode_opc_special2(CPUMIPSState *env, DisasContext *ctx) 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: + case OPC_DMOD_G_2F: + case OPC_DMODU_G_2F: + check_insn(ctx, INSN_LOONGSON2F); + gen_loongson_integer(ctx, op1, rd, rs, rt); + break; #endif - default: - if (ctx->insn_flags & ISA_MIPS32R6) { - decode_opc_special2_r6(env, ctx); - } else { - decode_opc_special2_legacy(env, ctx); - } + default: /* Invalid */ + MIPS_INVAL("special2_legacy"); + generate_exception(ctx, EXCP_RI); + break; } } @@ -15839,7 +15842,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx) decode_opc_special(env, ctx); break; case OPC_SPECIAL2: - decode_opc_special2(env, ctx); + decode_opc_special2_legacy(env, ctx); break; case OPC_SPECIAL3: decode_opc_special3(env, ctx); From 01f72885794124f94b24d97daf3c8630424cfd79 Mon Sep 17 00:00:00 2001 From: Leon Alrae Date: Fri, 27 Jun 2014 08:49:04 +0100 Subject: [PATCH 11/28] target-mips: Status.UX/SX/KX enable 32-bit address wrapping In R6 the special behaviour for data references is also specified for Kernel and Supervisor mode. Therefore MIPS_HFLAG_UX is replaced by generic MIPS_HFLAG_AWRAP indicating enabled 32-bit address wrapping. Signed-off-by: Leon Alrae Reviewed-by: Aurelien Jarno --- target-mips/cpu.h | 18 ++++++++++++++---- target-mips/translate.c | 6 +----- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/target-mips/cpu.h b/target-mips/cpu.h index 8b9a92ebdc..51a83318bd 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -450,7 +450,7 @@ struct CPUMIPSState { and RSQRT.D. */ #define MIPS_HFLAG_COP1X 0x00080 /* COP1X instructions enabled */ #define MIPS_HFLAG_RE 0x00100 /* Reversed endianness */ -#define MIPS_HFLAG_UX 0x00200 /* 64-bit user mode */ +#define MIPS_HFLAG_AWRAP 0x00200 /* 32-bit compatibility address wrapping */ #define MIPS_HFLAG_M16 0x00400 /* MIPS16 mode flag */ #define MIPS_HFLAG_M16_SHIFT 10 /* If translation is interrupted between the branch instruction and @@ -725,7 +725,7 @@ static inline void compute_hflags(CPUMIPSState *env) { env->hflags &= ~(MIPS_HFLAG_COP1X | MIPS_HFLAG_64 | MIPS_HFLAG_CP0 | MIPS_HFLAG_F64 | MIPS_HFLAG_FPU | MIPS_HFLAG_KSU | - MIPS_HFLAG_UX | MIPS_HFLAG_DSP | MIPS_HFLAG_DSPR2); + MIPS_HFLAG_AWRAP | MIPS_HFLAG_DSP | MIPS_HFLAG_DSPR2); if (!(env->CP0_Status & (1 << CP0St_EXL)) && !(env->CP0_Status & (1 << CP0St_ERL)) && !(env->hflags & MIPS_HFLAG_DM)) { @@ -737,8 +737,18 @@ static inline void compute_hflags(CPUMIPSState *env) (env->CP0_Status & (1 << CP0St_UX))) { env->hflags |= MIPS_HFLAG_64; } - if (env->CP0_Status & (1 << CP0St_UX)) { - env->hflags |= MIPS_HFLAG_UX; + + if (((env->hflags & MIPS_HFLAG_KSU) == MIPS_HFLAG_UM) && + !(env->CP0_Status & (1 << CP0St_UX))) { + env->hflags |= MIPS_HFLAG_AWRAP; + } else if (env->insn_flags & ISA_MIPS32R6) { + /* Address wrapping for Supervisor and Kernel is specified in R6 */ + if ((((env->hflags & MIPS_HFLAG_KSU) == MIPS_HFLAG_SM) && + !(env->CP0_Status & (1 << CP0St_SX))) || + (((env->hflags & MIPS_HFLAG_KSU) == MIPS_HFLAG_KM) && + !(env->CP0_Status & (1 << CP0St_KX)))) { + env->hflags |= MIPS_HFLAG_AWRAP; + } } #endif if ((env->CP0_Status & (1 << CP0St_CU0)) || diff --git a/target-mips/translate.c b/target-mips/translate.c index 34d63ea215..74204850a4 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -1383,11 +1383,7 @@ static inline void gen_op_addr_add (DisasContext *ctx, TCGv ret, TCGv arg0, TCGv tcg_gen_add_tl(ret, arg0, arg1); #if defined(TARGET_MIPS64) - /* For compatibility with 32-bit code, data reference in user mode - with Status_UX = 0 should be casted to 32-bit and sign extended. - See the MIPS64 PRA manual, section 4.10. */ - if (((ctx->hflags & MIPS_HFLAG_KSU) == MIPS_HFLAG_UM) && - !(ctx->hflags & MIPS_HFLAG_UX)) { + if (ctx->hflags & MIPS_HFLAG_AWRAP) { tcg_gen_ext32s_i64(ret, ret); } #endif From 15eacb9b525ad7f6b9326eeb8eeb151721d66570 Mon Sep 17 00:00:00 2001 From: Yongbok Kim Date: Fri, 27 Jun 2014 08:49:05 +0100 Subject: [PATCH 12/28] target-mips: add ALIGN, DALIGN, BITSWAP and DBITSWAP instructions Signed-off-by: Yongbok Kim Signed-off-by: Leon Alrae Reviewed-by: Aurelien Jarno --- disas/mips.c | 4 ++ target-mips/helper.h | 5 ++ target-mips/op_helper.c | 23 ++++++++ target-mips/translate.c | 120 ++++++++++++++++++++++++++++++++++++---- 4 files changed, 140 insertions(+), 12 deletions(-) diff --git a/disas/mips.c b/disas/mips.c index 8ee8758e50..61313f494c 100644 --- a/disas/mips.c +++ b/disas/mips.c @@ -1246,6 +1246,10 @@ const struct mips_opcode mips_builtin_opcodes[] = {"cache", "k,o(b)", 0x7c000025, 0xfc00007f, RD_b, 0, I32R6}, {"seleqz", "d,v,t", 0x00000035, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I32R6}, {"selnez", "d,v,t", 0x00000037, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I32R6}, +{"align", "d,v,t", 0x7c000220, 0xfc00073f, WR_d|RD_s|RD_t, 0, I32R6}, +{"dalign", "d,v,t", 0x7c000224, 0xfc00063f, WR_d|RD_s|RD_t, 0, I64R6}, +{"bitswap", "d,w", 0x7c000020, 0xffe007ff, WR_d|RD_t, 0, I32R6}, +{"dbitswap","d,w", 0x7c000024, 0xffe007ff, WR_d|RD_t, 0, I64R6}, {"pref", "k,o(b)", 0xcc000000, 0xfc000000, RD_b, 0, I4|I32|G3 }, {"prefx", "h,t(b)", 0x4c00000f, 0xfc0007ff, RD_b|RD_t, 0, I4|I33 }, {"nop", "", 0x00000000, 0xffffffff, 0, INSN2_ALIAS, I1 }, /* sll */ diff --git a/target-mips/helper.h b/target-mips/helper.h index 74ef09485f..5511dfcc3a 100644 --- a/target-mips/helper.h +++ b/target-mips/helper.h @@ -39,6 +39,11 @@ DEF_HELPER_3(macchiu, tl, env, tl, tl) DEF_HELPER_3(msachi, tl, env, tl, tl) DEF_HELPER_3(msachiu, tl, env, tl, tl) +DEF_HELPER_FLAGS_1(bitswap, TCG_CALL_NO_RWG_SE, tl, tl) +#ifdef TARGET_MIPS64 +DEF_HELPER_FLAGS_1(dbitswap, TCG_CALL_NO_RWG_SE, tl, tl) +#endif + #ifndef CONFIG_USER_ONLY /* CP0 helpers */ DEF_HELPER_1(mfc0_mvpcontrol, tl, env) diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index df97b35f87..c9841e26f8 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -266,6 +266,29 @@ target_ulong helper_mulshiu(CPUMIPSState *env, target_ulong arg1, (uint64_t)(uint32_t)arg2); } +static inline target_ulong bitswap(target_ulong v) +{ + v = ((v >> 1) & (target_ulong)0x5555555555555555) | + ((v & (target_ulong)0x5555555555555555) << 1); + v = ((v >> 2) & (target_ulong)0x3333333333333333) | + ((v & (target_ulong)0x3333333333333333) << 2); + v = ((v >> 4) & (target_ulong)0x0F0F0F0F0F0F0F0F) | + ((v & (target_ulong)0x0F0F0F0F0F0F0F0F) << 4); + return v; +} + +#ifdef TARGET_MIPS64 +target_ulong helper_dbitswap(target_ulong rt) +{ + return bitswap(rt); +} +#endif + +target_ulong helper_bitswap(target_ulong rt) +{ + return (int32_t)bitswap(rt); +} + #ifndef CONFIG_USER_ONLY static inline hwaddr do_translate_address(CPUMIPSState *env, diff --git a/target-mips/translate.c b/target-mips/translate.c index 74204850a4..0052e24617 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -392,17 +392,23 @@ enum { #define MASK_BSHFL(op) MASK_SPECIAL3(op) | (op & (0x1F << 6)) enum { - OPC_WSBH = (0x02 << 6) | OPC_BSHFL, - OPC_SEB = (0x10 << 6) | OPC_BSHFL, - OPC_SEH = (0x18 << 6) | OPC_BSHFL, + OPC_WSBH = (0x02 << 6) | OPC_BSHFL, + OPC_SEB = (0x10 << 6) | OPC_BSHFL, + OPC_SEH = (0x18 << 6) | OPC_BSHFL, + OPC_ALIGN = (0x08 << 6) | OPC_BSHFL, /* 010.bp */ + OPC_ALIGN_END = (0x0B << 6) | OPC_BSHFL, /* 010.00 to 010.11 */ + OPC_BITSWAP = (0x00 << 6) | OPC_BSHFL /* 00000 */ }; /* DBSHFL opcodes */ #define MASK_DBSHFL(op) MASK_SPECIAL3(op) | (op & (0x1F << 6)) enum { - OPC_DSBH = (0x02 << 6) | OPC_DBSHFL, - OPC_DSHD = (0x05 << 6) | OPC_DBSHFL, + OPC_DSBH = (0x02 << 6) | OPC_DBSHFL, + OPC_DSHD = (0x05 << 6) | OPC_DBSHFL, + OPC_DALIGN = (0x08 << 6) | OPC_DBSHFL, /* 01.bp */ + OPC_DALIGN_END = (0x0F << 6) | OPC_DBSHFL, /* 01.000 to 01.111 */ + OPC_DBITSWAP = (0x00 << 6) | OPC_DBSHFL, /* 00000 */ }; /* MIPS DSP REGIMM opcodes */ @@ -15162,12 +15168,14 @@ static void decode_opc_special2_legacy(CPUMIPSState *env, DisasContext *ctx) static void decode_opc_special3_r6(CPUMIPSState *env, DisasContext *ctx) { - int rs, rt; - uint32_t op1; + int rs, rt, rd, sa; + uint32_t op1, op2; int16_t imm; rs = (ctx->opcode >> 21) & 0x1f; rt = (ctx->opcode >> 16) & 0x1f; + rd = (ctx->opcode >> 11) & 0x1f; + sa = (ctx->opcode >> 6) & 0x1f; imm = (int16_t)ctx->opcode >> 7; op1 = MASK_SPECIAL3(ctx->opcode); @@ -15188,6 +15196,43 @@ static void decode_opc_special3_r6(CPUMIPSState *env, DisasContext *ctx) case R6_OPC_LL: gen_ld(ctx, op1, rt, rs, imm); break; + case OPC_BSHFL: + { + if (rd == 0) { + /* Treat as NOP. */ + break; + } + TCGv t0 = tcg_temp_new(); + gen_load_gpr(t0, rt); + + op2 = MASK_BSHFL(ctx->opcode); + switch (op2) { + case OPC_ALIGN ... OPC_ALIGN_END: + sa &= 3; + if (sa == 0) { + tcg_gen_mov_tl(cpu_gpr[rd], t0); + } else { + TCGv t1 = tcg_temp_new(); + TCGv_i64 t2 = tcg_temp_new_i64(); + gen_load_gpr(t1, rs); + tcg_gen_concat_tl_i64(t2, t1, t0); + tcg_gen_shri_i64(t2, t2, 8 * (4 - sa)); +#if defined(TARGET_MIPS64) + tcg_gen_ext32s_i64(cpu_gpr[rd], t2); +#else + tcg_gen_trunc_i64_i32(cpu_gpr[rd], t2); +#endif + tcg_temp_free_i64(t2); + tcg_temp_free(t1); + } + break; + case OPC_BITSWAP: + gen_helper_bitswap(cpu_gpr[rd], t0); + break; + } + tcg_temp_free(t0); + } + break; #if defined(TARGET_MIPS64) case R6_OPC_SCD: gen_st_cond(ctx, op1, rt, rs, imm); @@ -15195,6 +15240,38 @@ static void decode_opc_special3_r6(CPUMIPSState *env, DisasContext *ctx) case R6_OPC_LLD: gen_ld(ctx, op1, rt, rs, imm); break; + case OPC_DBSHFL: + check_mips_64(ctx); + { + if (rd == 0) { + /* Treat as NOP. */ + break; + } + TCGv t0 = tcg_temp_new(); + gen_load_gpr(t0, rt); + + op2 = MASK_DBSHFL(ctx->opcode); + switch (op2) { + case OPC_DALIGN ... OPC_DALIGN_END: + sa &= 7; + if (sa == 0) { + tcg_gen_mov_tl(cpu_gpr[rd], t0); + } else { + TCGv t1 = tcg_temp_new(); + gen_load_gpr(t1, rs); + tcg_gen_shli_tl(t0, t0, 8 * sa); + tcg_gen_shri_tl(t1, t1, 8 * (8 - sa)); + tcg_gen_or_tl(cpu_gpr[rd], t1, t0); + tcg_temp_free(t1); + } + break; + case OPC_DBITSWAP: + gen_helper_dbitswap(cpu_gpr[rd], t0); + break; + } + tcg_temp_free(t0); + } + break; #endif default: /* Invalid */ MIPS_INVAL("special3_r6"); @@ -15743,9 +15820,18 @@ static void decode_opc_special3(CPUMIPSState *env, DisasContext *ctx) gen_bitops(ctx, op1, rt, rs, sa, rd); break; case OPC_BSHFL: - check_insn(ctx, ISA_MIPS32R2); op2 = MASK_BSHFL(ctx->opcode); - gen_bshfl(ctx, op2, rt, rd); + switch (op2) { + case OPC_ALIGN ... OPC_ALIGN_END: + case OPC_BITSWAP: + check_insn(ctx, ISA_MIPS32R6); + decode_opc_special3_r6(env, ctx); + break; + default: + check_insn(ctx, ISA_MIPS32R2); + gen_bshfl(ctx, op2, rt, rd); + break; + } break; #if defined(TARGET_MIPS64) case OPC_DEXTM ... OPC_DEXT: @@ -15755,10 +15841,20 @@ static void decode_opc_special3(CPUMIPSState *env, DisasContext *ctx) gen_bitops(ctx, op1, rt, rs, sa, rd); break; case OPC_DBSHFL: - check_insn(ctx, ISA_MIPS64R2); - check_mips_64(ctx); op2 = MASK_DBSHFL(ctx->opcode); - gen_bshfl(ctx, op2, rt, rd); + switch (op2) { + case OPC_DALIGN ... OPC_DALIGN_END: + case OPC_DBITSWAP: + check_insn(ctx, ISA_MIPS32R6); + decode_opc_special3_r6(env, ctx); + break; + default: + check_insn(ctx, ISA_MIPS64R2); + check_mips_64(ctx); + op2 = MASK_DBSHFL(ctx->opcode); + gen_bshfl(ctx, op2, rt, rd); + break; + } break; #endif case OPC_RDHWR: From 31837be3eefed955504a3396d9baef8bcdec672e Mon Sep 17 00:00:00 2001 From: Yongbok Kim Date: Fri, 27 Jun 2014 08:49:05 +0100 Subject: [PATCH 13/28] target-mips: add compact and CP1 branches Introduce MIPS32R6 Compact Branch instructions which do not have delay slot - they have forbidden slot instead. However, current implementation does not support forbidden slot yet. Add also BC1EQZ and BC1NEZ instructions. Signed-off-by: Yongbok Kim Signed-off-by: Leon Alrae --- disas/mips.c | 67 +++++- target-mips/translate.c | 473 ++++++++++++++++++++++++++++++++++++++-- 2 files changed, 523 insertions(+), 17 deletions(-) diff --git a/disas/mips.c b/disas/mips.c index 61313f494c..823436990e 100644 --- a/disas/mips.c +++ b/disas/mips.c @@ -1250,6 +1250,34 @@ const struct mips_opcode mips_builtin_opcodes[] = {"dalign", "d,v,t", 0x7c000224, 0xfc00063f, WR_d|RD_s|RD_t, 0, I64R6}, {"bitswap", "d,w", 0x7c000020, 0xffe007ff, WR_d|RD_t, 0, I32R6}, {"dbitswap","d,w", 0x7c000024, 0xffe007ff, WR_d|RD_t, 0, I64R6}, +{"balc", "+p", 0xe8000000, 0xfc000000, UBD|WR_31, 0, I32R6}, +{"bc", "+p", 0xc8000000, 0xfc000000, UBD|WR_31, 0, I32R6}, +{"jic", "t,o", 0xd8000000, 0xffe00000, UBD|RD_t, 0, I32R6}, +{"beqzc", "s,+p", 0xd8000000, 0xfc000000, CBD|RD_s, 0, I32R6}, +{"jialc", "t,o", 0xf8000000, 0xffe00000, UBD|RD_t, 0, I32R6}, +{"bnezc", "s,+p", 0xf8000000, 0xfc000000, CBD|RD_s, 0, I32R6}, +{"beqzalc", "s,t,p", 0x20000000, 0xffe00000, CBD|RD_s|RD_t, 0, I32R6}, +{"bovc", "s,t,p", 0x20000000, 0xfc000000, CBD|RD_s|RD_t, 0, I32R6}, +{"beqc", "s,t,p", 0x20000000, 0xfc000000, CBD|RD_s|RD_t, 0, I32R6}, +{"bnezalc", "s,t,p", 0x60000000, 0xffe00000, CBD|RD_s|RD_t, 0, I32R6}, +{"bnvc", "s,t,p", 0x60000000, 0xfc000000, CBD|RD_s|RD_t, 0, I32R6}, +{"bnec", "s,t,p", 0x60000000, 0xfc000000, CBD|RD_s|RD_t, 0, I32R6}, +{"blezc", "s,t,p", 0x58000000, 0xffe00000, CBD|RD_s|RD_t, 0, I32R6}, +{"bgezc", "s,t,p", 0x58000000, 0xfc000000, CBD|RD_s|RD_t, 0, I32R6}, +{"bgec", "s,t,p", 0x58000000, 0xfc000000, CBD|RD_s|RD_t, 0, I32R6}, +{"bgtzc", "s,t,p", 0x5c000000, 0xffe00000, CBD|RD_s|RD_t, 0, I32R6}, +{"bltzc", "s,t,p", 0x5c000000, 0xfc000000, CBD|RD_s|RD_t, 0, I32R6}, +{"bltc", "s,t,p", 0x5c000000, 0xfc000000, CBD|RD_s|RD_t, 0, I32R6}, +{"blezalc", "s,t,p", 0x18000000, 0xffe00000, CBD|RD_s|RD_t, 0, I32R6}, +{"bgezalc", "s,t,p", 0x18000000, 0xfc000000, CBD|RD_s|RD_t, 0, I32R6}, +{"bgeuc", "s,t,p", 0x18000000, 0xfc000000, CBD|RD_s|RD_t, 0, I32R6}, +{"bgtzalc", "s,t,p", 0x1c000000, 0xffe00000, CBD|RD_s|RD_t, 0, I32R6}, +{"bltzalc", "s,t,p", 0x1c000000, 0xfc000000, CBD|RD_s|RD_t, 0, I32R6}, +{"bltuc", "s,t,p", 0x1c000000, 0xfc000000, CBD|RD_s|RD_t, 0, I32R6}, +{"bc1eqz", "T,p", 0x45200000, 0xffe00000, CBD|RD_T|FP_S|FP_D, 0, I32R6}, +{"bc1nez", "T,p", 0x45a00000, 0xffe00000, CBD|RD_T|FP_S|FP_D, 0, I32R6}, +{"bc2eqz", "E,p", 0x49200000, 0xffe00000, CBD|RD_C2, 0, I32R6}, +{"bc2nez", "E,p", 0x49a00000, 0xffe00000, CBD|RD_C2, 0, I32R6}, {"pref", "k,o(b)", 0xcc000000, 0xfc000000, RD_b, 0, I4|I32|G3 }, {"prefx", "h,t(b)", 0x4c00000f, 0xfc0007ff, RD_b|RD_t, 0, I4|I33 }, {"nop", "", 0x00000000, 0xffffffff, 0, INSN2_ALIAS, I1 }, /* sll */ @@ -3616,6 +3644,24 @@ print_insn_args (const char *d, (*info->fprintf_func) (info->stream, "0x%x", msbd + 1); break; + case 'o': + delta = (l >> OP_SH_DELTA_R6) & OP_MASK_DELTA_R6; + if (delta & 0x8000) { + delta |= ~0xffff; + } + (*info->fprintf_func) (info->stream, "%d", delta); + break; + + case 'p': + /* Sign extend the displacement with 26 bits. */ + delta = (l >> OP_SH_DELTA) & OP_MASK_TARGET; + if (delta & 0x2000000) { + delta |= ~0x3FFFFFF; + } + info->target = (delta << 2) + pc + INSNLEN; + (*info->print_address_func) (info->target, info); + break; + case 't': /* Coprocessor 0 reg name */ (*info->fprintf_func) (info->stream, "%s", mips_cp0_names[(l >> OP_SH_RT) & @@ -3767,9 +3813,7 @@ print_insn_args (const char *d, case 'j': /* Same as i, but sign-extended. */ case 'o': - delta = (opp->membership == I32R6) ? - (l >> OP_SH_DELTA_R6) & OP_MASK_DELTA_R6 : - (l >> OP_SH_DELTA) & OP_MASK_DELTA; + delta = (l >> OP_SH_DELTA) & OP_MASK_DELTA; if (delta & 0x8000) delta |= ~0xffff; @@ -4096,6 +4140,23 @@ print_insn_mips (bfd_vma memaddr, && strcmp (op->name, "jalx")) continue; + if (strcmp(op->name, "bovc") == 0 + || strcmp(op->name, "bnvc") == 0) { + if (((word >> OP_SH_RS) & OP_MASK_RS) < + ((word >> OP_SH_RT) & OP_MASK_RT)) { + continue; + } + } + if (strcmp(op->name, "bgezc") == 0 + || strcmp(op->name, "bltzc") == 0 + || strcmp(op->name, "bgezalc") == 0 + || strcmp(op->name, "bltzalc") == 0) { + if (((word >> OP_SH_RS) & OP_MASK_RS) != + ((word >> OP_SH_RT) & OP_MASK_RT)) { + continue; + } + } + /* Figure out instruction type and branch delay information. */ if ((op->pinfo & INSN_UNCOND_BRANCH_DELAY) != 0) { diff --git a/target-mips/translate.c b/target-mips/translate.c index 0052e24617..06ececb426 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -111,6 +111,31 @@ enum { OPC_SWC2 = (0x3A << 26), OPC_SDC1 = (0x3D << 26), OPC_SDC2 = (0x3E << 26), + /* Compact Branches */ + OPC_BLEZALC = (0x06 << 26), + OPC_BGEZALC = (0x06 << 26), + OPC_BGEUC = (0x06 << 26), + OPC_BGTZALC = (0x07 << 26), + OPC_BLTZALC = (0x07 << 26), + OPC_BLTUC = (0x07 << 26), + OPC_BOVC = (0x08 << 26), + OPC_BEQZALC = (0x08 << 26), + OPC_BEQC = (0x08 << 26), + OPC_BLEZC = (0x16 << 26), + OPC_BGEZC = (0x16 << 26), + OPC_BGEC = (0x16 << 26), + OPC_BGTZC = (0x17 << 26), + OPC_BLTZC = (0x17 << 26), + OPC_BLTC = (0x17 << 26), + OPC_BNVC = (0x18 << 26), + OPC_BNEZALC = (0x18 << 26), + OPC_BNEC = (0x18 << 26), + OPC_BC = (0x32 << 26), + OPC_BEQZC = (0x36 << 26), + OPC_JIC = (0x36 << 26), + OPC_BALC = (0x3A << 26), + OPC_BNEZC = (0x3E << 26), + OPC_JIALC = (0x3E << 26), /* MDMX ASE specific */ OPC_MDMX = (0x1E << 26), /* Cache and prefetch */ @@ -897,6 +922,8 @@ enum { OPC_W_FMT = (FMT_W << 21) | OPC_CP1, OPC_L_FMT = (FMT_L << 21) | OPC_CP1, OPC_PS_FMT = (FMT_PS << 21) | OPC_CP1, + OPC_BC1EQZ = (0x09 << 21) | OPC_CP1, + OPC_BC1NEZ = (0x0D << 21) | OPC_CP1, }; #define MASK_CP1_FUNC(op) MASK_CP1(op) | (op & 0x3F) @@ -931,6 +958,8 @@ enum { OPC_CTC2 = (0x06 << 21) | OPC_CP2, OPC_MTHC2 = (0x07 << 21) | OPC_CP2, OPC_BC2 = (0x08 << 21) | OPC_CP2, + OPC_BC2EQZ = (0x09 << 21) | OPC_CP2, + OPC_BC2NEZ = (0x0D << 21) | OPC_CP2, }; #define MASK_LMI(op) (MASK_OP_MAJOR(op) | (op & (0x1F << 21)) | (op & 0x1F)) @@ -1395,6 +1424,20 @@ static inline void gen_op_addr_add (DisasContext *ctx, TCGv ret, TCGv arg0, TCGv #endif } +/* Addresses computation (translation time) */ +static target_long addr_add(DisasContext *ctx, target_long base, + target_long offset) +{ + target_long sum = base + offset; + +#if defined(TARGET_MIPS64) + if (ctx->hflags & MIPS_HFLAG_AWRAP) { + sum = (int32_t)sum; + } +#endif + return sum; +} + static inline void check_cp0_enabled(DisasContext *ctx) { if (unlikely(!(ctx->hflags & MIPS_HFLAG_CP0))) @@ -7433,6 +7476,55 @@ static void gen_compute_branch1(DisasContext *ctx, uint32_t op, tcg_temp_free_i32(t0); } +/* R6 CP1 Branches */ +static void gen_compute_branch1_r6(DisasContext *ctx, uint32_t op, + int32_t ft, int32_t offset) +{ + target_ulong btarget; + const char *opn = "cp1 cond branch"; + TCGv_i64 t0 = tcg_temp_new_i64(); + + if (ctx->hflags & MIPS_HFLAG_BMASK) { +#ifdef MIPS_DEBUG_DISAS + LOG_DISAS("Branch in delay slot at PC 0x" TARGET_FMT_lx "\n", ctx->pc); +#endif + generate_exception(ctx, EXCP_RI); + goto out; + } + + gen_load_fpr64(ctx, t0, ft); + tcg_gen_andi_i64(t0, t0, 1); + + btarget = addr_add(ctx, ctx->pc + 4, offset); + + switch (op) { + case OPC_BC1EQZ: + tcg_gen_xori_i64(t0, t0, 1); + opn = "bc1eqz"; + ctx->hflags |= MIPS_HFLAG_BC; + break; + case OPC_BC1NEZ: + /* t0 already set */ + opn = "bc1nez"; + ctx->hflags |= MIPS_HFLAG_BC; + break; + default: + MIPS_INVAL(opn); + generate_exception(ctx, EXCP_RI); + goto out; + } + + tcg_gen_trunc_i64_tl(bcond, t0); + + (void)opn; /* avoid a compiler warning */ + MIPS_DEBUG("%s: cond %02x target " TARGET_FMT_lx, opn, + ctx->hflags, btarget); + ctx->btarget = btarget; + +out: + tcg_temp_free_i64(t0); +} + /* Coprocessor 1 (FPU) */ #define FOP(func, fmt) (((fmt) << 21) | (func)) @@ -9438,7 +9530,7 @@ static void gen_rdhwr(DisasContext *ctx, int rt, int rd) tcg_temp_free(t0); } -static void handle_delay_slot(DisasContext *ctx, int insn_bytes) +static void gen_branch(DisasContext *ctx, int insn_bytes) { if (ctx->hflags & MIPS_HFLAG_BMASK) { int proc_hflags = ctx->hflags & MIPS_HFLAG_BMASK; @@ -14757,6 +14849,242 @@ static void gen_mipsdsp_accinsn(DisasContext *ctx, uint32_t op1, uint32_t op2, /* End MIPSDSP functions. */ +/* Compact Branches */ +static void gen_compute_compact_branch(DisasContext *ctx, uint32_t opc, + int rs, int rt, int32_t offset) +{ + int bcond_compute = 0; + TCGv t0 = tcg_temp_new(); + TCGv t1 = tcg_temp_new(); + + if (ctx->hflags & MIPS_HFLAG_BMASK) { +#ifdef MIPS_DEBUG_DISAS + LOG_DISAS("Branch in delay slot at PC 0x" TARGET_FMT_lx "\n", ctx->pc); +#endif + generate_exception(ctx, EXCP_RI); + goto out; + } + + /* Load needed operands and calculate btarget */ + switch (opc) { + /* compact branch */ + case OPC_BOVC: /* OPC_BEQZALC, OPC_BEQC */ + case OPC_BNVC: /* OPC_BNEZALC, OPC_BNEC */ + gen_load_gpr(t0, rs); + gen_load_gpr(t1, rt); + bcond_compute = 1; + ctx->btarget = addr_add(ctx, ctx->pc + 4, offset); + if (rs <= rt && rs == 0) { + /* OPC_BEQZALC, OPC_BNEZALC */ + tcg_gen_movi_tl(cpu_gpr[31], ctx->pc + 4); + } + break; + case OPC_BLEZC: /* OPC_BGEZC, OPC_BGEC */ + case OPC_BGTZC: /* OPC_BLTZC, OPC_BLTC */ + gen_load_gpr(t0, rs); + gen_load_gpr(t1, rt); + bcond_compute = 1; + ctx->btarget = addr_add(ctx, ctx->pc + 4, offset); + break; + case OPC_BLEZALC: /* OPC_BGEZALC, OPC_BGEUC */ + case OPC_BGTZALC: /* OPC_BLTZALC, OPC_BLTUC */ + if (rs == 0 || rs == rt) { + /* OPC_BLEZALC, OPC_BGEZALC */ + /* OPC_BGTZALC, OPC_BLTZALC */ + tcg_gen_movi_tl(cpu_gpr[31], ctx->pc + 4); + } + gen_load_gpr(t0, rs); + gen_load_gpr(t1, rt); + bcond_compute = 1; + ctx->btarget = addr_add(ctx, ctx->pc + 4, offset); + break; + case OPC_BC: + case OPC_BALC: + ctx->btarget = addr_add(ctx, ctx->pc + 4, offset); + break; + case OPC_BEQZC: + case OPC_BNEZC: + if (rs != 0) { + /* OPC_BEQZC, OPC_BNEZC */ + gen_load_gpr(t0, rs); + bcond_compute = 1; + ctx->btarget = addr_add(ctx, ctx->pc + 4, offset); + } else { + /* OPC_JIC, OPC_JIALC */ + TCGv tbase = tcg_temp_new(); + TCGv toffset = tcg_temp_new(); + + gen_load_gpr(tbase, rt); + tcg_gen_movi_tl(toffset, offset); + gen_op_addr_add(ctx, btarget, tbase, toffset); + tcg_temp_free(tbase); + tcg_temp_free(toffset); + } + break; + default: + MIPS_INVAL("Compact branch/jump"); + generate_exception(ctx, EXCP_RI); + goto out; + } + + if (bcond_compute == 0) { + /* Uncoditional compact branch */ + switch (opc) { + case OPC_JIALC: + tcg_gen_movi_tl(cpu_gpr[31], ctx->pc + 4); + /* Fallthrough */ + case OPC_JIC: + ctx->hflags |= MIPS_HFLAG_BR; + break; + case OPC_BALC: + tcg_gen_movi_tl(cpu_gpr[31], ctx->pc + 4); + /* Fallthrough */ + case OPC_BC: + ctx->hflags |= MIPS_HFLAG_B; + break; + default: + MIPS_INVAL("Compact branch/jump"); + generate_exception(ctx, EXCP_RI); + goto out; + } + + /* Generating branch here as compact branches don't have delay slot */ + gen_branch(ctx, 4); + } else { + /* Conditional compact branch */ + int l1 = gen_new_label(); + save_cpu_state(ctx, 0); + + switch (opc) { + case OPC_BLEZALC: /* OPC_BGEZALC, OPC_BGEUC */ + if (rs == 0 && rt != 0) { + /* OPC_BLEZALC */ + tcg_gen_brcondi_tl(TCG_COND_LE, t1, 0, l1); + } else if (rs != 0 && rt != 0 && rs == rt) { + /* OPC_BGEZALC */ + tcg_gen_brcondi_tl(TCG_COND_GE, t1, 0, l1); + } else { + /* OPC_BGEUC */ + tcg_gen_brcond_tl(TCG_COND_GEU, t0, t1, l1); + } + break; + case OPC_BGTZALC: /* OPC_BLTZALC, OPC_BLTUC */ + if (rs == 0 && rt != 0) { + /* OPC_BGTZALC */ + tcg_gen_brcondi_tl(TCG_COND_GT, t1, 0, l1); + } else if (rs != 0 && rt != 0 && rs == rt) { + /* OPC_BLTZALC */ + tcg_gen_brcondi_tl(TCG_COND_LT, t1, 0, l1); + } else { + /* OPC_BLTUC */ + tcg_gen_brcond_tl(TCG_COND_LTU, t0, t1, l1); + } + break; + case OPC_BLEZC: /* OPC_BGEZC, OPC_BGEC */ + if (rs == 0 && rt != 0) { + /* OPC_BLEZC */ + tcg_gen_brcondi_tl(TCG_COND_LE, t1, 0, l1); + } else if (rs != 0 && rt != 0 && rs == rt) { + /* OPC_BGEZC */ + tcg_gen_brcondi_tl(TCG_COND_GE, t1, 0, l1); + } else { + /* OPC_BGEC */ + tcg_gen_brcond_tl(TCG_COND_GE, t0, t1, l1); + } + break; + case OPC_BGTZC: /* OPC_BLTZC, OPC_BLTC */ + if (rs == 0 && rt != 0) { + /* OPC_BGTZC */ + tcg_gen_brcondi_tl(TCG_COND_GT, t1, 0, l1); + } else if (rs != 0 && rt != 0 && rs == rt) { + /* OPC_BLTZC */ + tcg_gen_brcondi_tl(TCG_COND_LT, t1, 0, l1); + } else { + /* OPC_BLTC */ + tcg_gen_brcond_tl(TCG_COND_LT, t0, t1, l1); + } + break; + case OPC_BOVC: /* OPC_BEQZALC, OPC_BEQC */ + case OPC_BNVC: /* OPC_BNEZALC, OPC_BNEC */ + if (rs >= rt) { + /* OPC_BOVC, OPC_BNVC */ + TCGv t2 = tcg_temp_new(); + TCGv t3 = tcg_temp_new(); + TCGv t4 = tcg_temp_new(); + TCGv input_overflow = tcg_temp_new(); + + gen_load_gpr(t0, rs); + gen_load_gpr(t1, rt); + tcg_gen_ext32s_tl(t2, t0); + tcg_gen_setcond_tl(TCG_COND_NE, input_overflow, t2, t0); + tcg_gen_ext32s_tl(t3, t1); + tcg_gen_setcond_tl(TCG_COND_NE, t4, t3, t1); + tcg_gen_or_tl(input_overflow, input_overflow, t4); + + tcg_gen_add_tl(t4, t2, t3); + tcg_gen_ext32s_tl(t4, t4); + tcg_gen_xor_tl(t2, t2, t3); + tcg_gen_xor_tl(t3, t4, t3); + tcg_gen_andc_tl(t2, t3, t2); + tcg_gen_setcondi_tl(TCG_COND_LT, t4, t2, 0); + tcg_gen_or_tl(t4, t4, input_overflow); + if (opc == OPC_BOVC) { + /* OPC_BOVC */ + tcg_gen_brcondi_tl(TCG_COND_NE, t4, 0, l1); + } else { + /* OPC_BNVC */ + tcg_gen_brcondi_tl(TCG_COND_EQ, t4, 0, l1); + } + tcg_temp_free(input_overflow); + tcg_temp_free(t4); + tcg_temp_free(t3); + tcg_temp_free(t2); + } else if (rs < rt && rs == 0) { + /* OPC_BEQZALC, OPC_BNEZALC */ + if (opc == OPC_BEQZALC) { + /* OPC_BEQZALC */ + tcg_gen_brcondi_tl(TCG_COND_EQ, t1, 0, l1); + } else { + /* OPC_BNEZALC */ + tcg_gen_brcondi_tl(TCG_COND_NE, t1, 0, l1); + } + } else { + /* OPC_BEQC, OPC_BNEC */ + if (opc == OPC_BEQC) { + /* OPC_BEQC */ + tcg_gen_brcond_tl(TCG_COND_EQ, t0, t1, l1); + } else { + /* OPC_BNEC */ + tcg_gen_brcond_tl(TCG_COND_NE, t0, t1, l1); + } + } + break; + case OPC_BEQZC: + tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 0, l1); + break; + case OPC_BNEZC: + tcg_gen_brcondi_tl(TCG_COND_NE, t0, 0, l1); + break; + default: + MIPS_INVAL("Compact conditional branch/jump"); + generate_exception(ctx, EXCP_RI); + goto out; + } + + /* Generating branch here as compact branches don't have delay slot */ + /* TODO: implement forbidden slot */ + gen_goto_tb(ctx, 1, ctx->pc + 4); + gen_set_label(l1); + gen_goto_tb(ctx, 0, ctx->btarget); + MIPS_DEBUG("Compact conditional branch"); + ctx->bstate = BS_BRANCH; + } + +out: + tcg_temp_free(t0); + tcg_temp_free(t1); +} + static void decode_opc_special_r6(CPUMIPSState *env, DisasContext *ctx) { int rs, rt, rd, sa; @@ -16063,7 +16391,16 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx) break; } break; - case OPC_ADDI: /* Arithmetic with immediate opcode */ + case OPC_BOVC: /* OPC_BEQZALC, OPC_BEQC, OPC_ADDI */ + if (ctx->insn_flags & ISA_MIPS32R6) { + /* OPC_BOVC, OPC_BEQZALC, OPC_BEQC */ + gen_compute_compact_branch(ctx, op, rs, rt, imm << 2); + } else { + /* OPC_ADDI */ + /* Arithmetic with immediate opcode */ + gen_arith_imm(ctx, op, rt, rs, imm); + } + break; case OPC_ADDIU: gen_arith_imm(ctx, op, rt, rs, imm); break; @@ -16081,9 +16418,58 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx) offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 2; gen_compute_branch(ctx, op, 4, rs, rt, offset); break; - case OPC_BEQL ... OPC_BGTZL: /* Branch */ + /* Branch */ + case OPC_BLEZC: /* OPC_BGEZC, OPC_BGEC, OPC_BLEZL */ + if (ctx->insn_flags & ISA_MIPS32R6) { + if (rt == 0) { + generate_exception(ctx, EXCP_RI); + break; + } + /* OPC_BLEZC, OPC_BGEZC, OPC_BGEC */ + gen_compute_compact_branch(ctx, op, rs, rt, imm << 2); + } else { + /* OPC_BLEZL */ + gen_compute_branch(ctx, op, 4, rs, rt, imm << 2); + } + break; + case OPC_BGTZC: /* OPC_BLTZC, OPC_BLTC, OPC_BGTZL */ + if (ctx->insn_flags & ISA_MIPS32R6) { + if (rt == 0) { + generate_exception(ctx, EXCP_RI); + break; + } + /* OPC_BGTZC, OPC_BLTZC, OPC_BLTC */ + gen_compute_compact_branch(ctx, op, rs, rt, imm << 2); + } else { + /* OPC_BGTZL */ + gen_compute_branch(ctx, op, 4, rs, rt, imm << 2); + } + break; + case OPC_BLEZALC: /* OPC_BGEZALC, OPC_BGEUC, OPC_BLEZ */ + if (rt == 0) { + /* OPC_BLEZ */ + gen_compute_branch(ctx, op, 4, rs, rt, imm << 2); + } else { + check_insn(ctx, ISA_MIPS32R6); + /* OPC_BLEZALC, OPC_BGEZALC, OPC_BGEUC */ + gen_compute_compact_branch(ctx, op, rs, rt, imm << 2); + } + break; + case OPC_BGTZALC: /* OPC_BLTZALC, OPC_BLTUC, OPC_BGTZ */ + if (rt == 0) { + /* OPC_BGTZ */ + gen_compute_branch(ctx, op, 4, rs, rt, imm << 2); + } else { + check_insn(ctx, ISA_MIPS32R6); + /* OPC_BGTZALC, OPC_BLTZALC, OPC_BLTUC */ + gen_compute_compact_branch(ctx, op, rs, rt, imm << 2); + } + break; + case OPC_BEQL: + case OPC_BNEL: check_insn_opc_removed(ctx, ISA_MIPS32R6); - case OPC_BEQ ... OPC_BGTZ: + case OPC_BEQ: + case OPC_BNE: gen_compute_branch(ctx, op, 4, rs, rt, imm << 2); break; case OPC_LWL: /* Load and stores */ @@ -16146,7 +16532,24 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx) gen_cp1(ctx, op1, rt, rd); break; #endif - case OPC_BC1ANY2: + case OPC_BC1EQZ: /* OPC_BC1ANY2 */ + if (ctx->insn_flags & ISA_MIPS32R6) { + /* OPC_BC1EQZ */ + gen_compute_branch1_r6(ctx, MASK_CP1(ctx->opcode), + rt, imm << 2); + } else { + /* OPC_BC1ANY2 */ + check_cop1x(ctx); + check_insn(ctx, ASE_MIPS3D); + gen_compute_branch1(ctx, MASK_BC1(ctx->opcode), + (rt >> 2) & 0x7, imm << 2); + } + break; + case OPC_BC1NEZ: + check_insn(ctx, ISA_MIPS32R6); + gen_compute_branch1_r6(ctx, MASK_CP1(ctx->opcode), + rt, imm << 2); + break; case OPC_BC1ANY4: check_insn_opc_removed(ctx, ISA_MIPS32R6); check_cop1x(ctx); @@ -16176,13 +16579,35 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx) } break; - /* COP2. */ - case OPC_LWC2: - case OPC_LDC2: - case OPC_SWC2: - case OPC_SDC2: - /* COP2: Not implemented. */ - generate_exception_err(ctx, EXCP_CpU, 2); + /* Compact branches [R6] and COP2 [non-R6] */ + case OPC_BC: /* OPC_LWC2 */ + case OPC_BALC: /* OPC_SWC2 */ + if (ctx->insn_flags & ISA_MIPS32R6) { + /* OPC_BC, OPC_BALC */ + gen_compute_compact_branch(ctx, op, 0, 0, + sextract32(ctx->opcode << 2, 0, 28)); + } else { + /* OPC_LWC2, OPC_SWC2 */ + /* COP2: Not implemented. */ + generate_exception_err(ctx, EXCP_CpU, 2); + } + break; + case OPC_BEQZC: /* OPC_JIC, OPC_LDC2 */ + case OPC_BNEZC: /* OPC_JIALC, OPC_SDC2 */ + if (ctx->insn_flags & ISA_MIPS32R6) { + if (rs != 0) { + /* OPC_BEQZC, OPC_BNEZC */ + gen_compute_compact_branch(ctx, op, rs, 0, + sextract32(ctx->opcode << 2, 0, 23)); + } else { + /* OPC_JIC, OPC_JIALC */ + gen_compute_compact_branch(ctx, op, 0, rt, imm); + } + } else { + /* OPC_LWC2, OPC_SWC2 */ + /* COP2: Not implemented. */ + generate_exception_err(ctx, EXCP_CpU, 2); + } break; case OPC_CP2: check_insn(ctx, INSN_LOONGSON2F); @@ -16256,12 +16681,31 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx) check_mips_64(ctx); gen_st_cond(ctx, op, rt, rs, imm); break; - case OPC_DADDI: + case OPC_BNVC: /* OPC_BNEZALC, OPC_BNEC, OPC_DADDI */ + if (ctx->insn_flags & ISA_MIPS32R6) { + /* OPC_BNVC, OPC_BNEZALC, OPC_BNEC */ + gen_compute_compact_branch(ctx, op, rs, rt, imm << 2); + } else { + /* OPC_DADDI */ + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); + gen_arith_imm(ctx, op, rt, rs, imm); + } + break; case OPC_DADDIU: check_insn(ctx, ISA_MIPS3); check_mips_64(ctx); gen_arith_imm(ctx, op, rt, rs, imm); break; +#else + case OPC_BNVC: /* OPC_BNEZALC, OPC_BNEC */ + if (ctx->insn_flags & ISA_MIPS32R6) { + gen_compute_compact_branch(ctx, op, rs, rt, imm << 2); + } else { + MIPS_INVAL("major opcode"); + generate_exception(ctx, EXCP_RI); + } + break; #endif case OPC_JALX: check_insn(ctx, ASE_MIPS16 | ASE_MICROMIPS); @@ -16368,8 +16812,9 @@ gen_intermediate_code_internal(MIPSCPU *cpu, TranslationBlock *tb, ctx.bstate = BS_STOP; break; } + if (is_delay) { - handle_delay_slot(&ctx, insn_bytes); + gen_branch(&ctx, insn_bytes); } ctx.pc += insn_bytes; From d4ea6acdf60db1d8373543e1557ba908f5d5479b Mon Sep 17 00:00:00 2001 From: Leon Alrae Date: Fri, 27 Jun 2014 08:49:06 +0100 Subject: [PATCH 14/28] target-mips: add AUI, LSA and PCREL instruction families Signed-off-by: Leon Alrae Reviewed-by: Yongbok Kim --- disas/mips.c | 42 ++++++++- target-mips/translate.c | 203 +++++++++++++++++++++++++++++++++++++--- 2 files changed, 228 insertions(+), 17 deletions(-) diff --git a/disas/mips.c b/disas/mips.c index 823436990e..850cb65dd7 100644 --- a/disas/mips.c +++ b/disas/mips.c @@ -407,6 +407,12 @@ struct mips_opcode "+3" UDI immediate bits 6-20 "+4" UDI immediate bits 6-25 + R6 immediates/displacements : + (adding suffix to 'o' to avoid adding new characters) + "+o" 9 bits immediate/displacement (shift = 7) + "+o1" 18 bits immediate/displacement (shift = 0) + "+o2" 19 bits immediate/displacement (shift = 0) + Other: "()" parens surrounding optional value "," separates operands @@ -1217,6 +1223,17 @@ const struct mips_opcode mips_builtin_opcodes[] = them first. The assemblers uses a hash table based on the instruction name anyhow. */ /* name, args, match, mask, pinfo, membership */ +{"lwpc", "s,+o2", 0xec080000, 0xfc180000, WR_d, 0, I32R6}, +{"lwupc", "s,+o2", 0xec100000, 0xfc180000, WR_d, 0, I64R6}, +{"ldpc", "s,+o1", 0xec180000, 0xfc1c0000, WR_d, 0, I64R6}, +{"addiupc", "s,+o2", 0xec000000, 0xfc180000, WR_d, 0, I32R6}, +{"auipc", "s,u", 0xec1e0000, 0xfc1f0000, WR_d, 0, I32R6}, +{"aluipc", "s,u", 0xec1f0000, 0xfc1f0000, WR_d, 0, I32R6}, +{"daui", "s,t,u", 0x74000000, 0xfc000000, RD_s|WR_t, 0, I64R6}, +{"dahi", "s,u", 0x04060000, 0xfc1f0000, RD_s, 0, I64R6}, +{"dati", "s,u", 0x041e0000, 0xfc1f0000, RD_s, 0, I64R6}, +{"lsa", "d,s,t", 0x00000005, 0xfc00073f, WR_d|RD_s|RD_t, 0, I32R6}, +{"dlsa", "d,s,t", 0x00000015, 0xfc00073f, WR_d|RD_s|RD_t, 0, I64R6}, {"clz", "U,s", 0x00000050, 0xfc1f07ff, WR_d|RD_s, 0, I32R6}, {"clo", "U,s", 0x00000051, 0xfc1f07ff, WR_d|RD_s, 0, I32R6}, {"dclz", "U,s", 0x00000052, 0xfc1f07ff, WR_d|RD_s, 0, I64R6}, @@ -1822,6 +1839,7 @@ const struct mips_opcode mips_builtin_opcodes[] = {"lld", "t,o(b)", 0xd0000000, 0xfc000000, LDD|RD_b|WR_t, 0, I3 }, {"lld", "t,A(b)", 0, (int) M_LLD_AB, INSN_MACRO, 0, I3 }, {"lui", "t,u", 0x3c000000, 0xffe00000, WR_t, 0, I1 }, +{"aui", "s,t,u", 0x3c000000, 0xfc000000, RD_s|WR_t, 0, I32R6}, {"luxc1", "D,t(b)", 0x4c000005, 0xfc00f83f, LDD|WR_D|RD_t|RD_b|FP_D, 0, I5|I33|N55}, {"lw", "t,o(b)", 0x8c000000, 0xfc000000, LDD|RD_b|WR_t, 0, I1 }, {"lw", "t,A(b)", 0, (int) M_LW_AB, INSN_MACRO, 0, I1 }, @@ -3645,10 +3663,28 @@ print_insn_args (const char *d, break; case 'o': - delta = (l >> OP_SH_DELTA_R6) & OP_MASK_DELTA_R6; - if (delta & 0x8000) { - delta |= ~0xffff; + switch (*(d+1)) { + case '1': + d++; + delta = l & ((1 << 18) - 1); + if (delta & 0x20000) { + delta |= ~0x1ffff; + } + break; + case '2': + d++; + delta = l & ((1 << 19) - 1); + if (delta & 0x40000) { + delta |= ~0x3ffff; + } + break; + default: + delta = (l >> OP_SH_DELTA_R6) & OP_MASK_DELTA_R6; + if (delta & 0x8000) { + delta |= ~0xffff; + } } + (*info->fprintf_func) (info->stream, "%d", delta); break; diff --git a/target-mips/translate.c b/target-mips/translate.c index 06ececb426..45ff5fc094 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -75,6 +75,7 @@ enum { OPC_BGTZ = (0x07 << 26), OPC_BGTZL = (0x17 << 26), OPC_JALX = (0x1D << 26), /* MIPS 16 only */ + OPC_DAUI = (0x1D << 26), OPC_JALXS = OPC_JALX | 0x5, /* Load and stores */ OPC_LDL = (0x1A << 26), @@ -141,8 +142,25 @@ enum { /* Cache and prefetch */ OPC_CACHE = (0x2F << 26), OPC_PREF = (0x33 << 26), - /* Reserved major opcode */ - OPC_MAJOR3B_RESERVED = (0x3B << 26), + /* PC-relative address computation / loads */ + OPC_PCREL = (0x3B << 26), +}; + +/* PC-relative address computation / loads */ +#define MASK_OPC_PCREL_TOP2BITS(op) (MASK_OP_MAJOR(op) | (op & (3 << 19))) +#define MASK_OPC_PCREL_TOP5BITS(op) (MASK_OP_MAJOR(op) | (op & (0x1f << 16))) +enum { + /* Instructions determined by bits 19 and 20 */ + OPC_ADDIUPC = OPC_PCREL | (0 << 19), + R6_OPC_LWPC = OPC_PCREL | (1 << 19), + OPC_LWUPC = OPC_PCREL | (2 << 19), + + /* Instructions determined by bits 16 ... 20 */ + OPC_AUIPC = OPC_PCREL | (0x1e << 16), + OPC_ALUIPC = OPC_PCREL | (0x1f << 16), + + /* Other */ + R6_OPC_LDPC = OPC_PCREL | (6 << 18), }; /* MIPS special opcodes */ @@ -231,7 +249,6 @@ enum { OPC_SPIM = 0x0E | OPC_SPECIAL, /* unofficial */ OPC_SYNC = 0x0F | OPC_SPECIAL, - OPC_SPECIAL15_RESERVED = 0x15 | OPC_SPECIAL, OPC_SPECIAL28_RESERVED = 0x28 | OPC_SPECIAL, OPC_SPECIAL29_RESERVED = 0x29 | OPC_SPECIAL, OPC_SPECIAL39_RESERVED = 0x39 | OPC_SPECIAL, @@ -266,6 +283,9 @@ enum { R6_OPC_DCLZ = 0x12 | OPC_SPECIAL, R6_OPC_DCLO = 0x13 | OPC_SPECIAL, R6_OPC_SDBBP = 0x0e | OPC_SPECIAL, + + OPC_LSA = 0x05 | OPC_SPECIAL, + OPC_DLSA = 0x15 | OPC_SPECIAL, }; /* Multiplication variants of the vr54xx. */ @@ -309,6 +329,9 @@ enum { OPC_TEQI = (0x0C << 16) | OPC_REGIMM, OPC_TNEI = (0x0E << 16) | OPC_REGIMM, OPC_SYNCI = (0x1F << 16) | OPC_REGIMM, + + OPC_DAHI = (0x06 << 16) | OPC_REGIMM, + OPC_DATI = (0x1e << 16) | OPC_REGIMM, }; /* Special2 opcodes */ @@ -2162,8 +2185,15 @@ static void gen_logic_imm(DisasContext *ctx, uint32_t opc, regnames[rs], uimm); break; case OPC_LUI: - tcg_gen_movi_tl(cpu_gpr[rt], imm << 16); - MIPS_DEBUG("lui %s, " TARGET_FMT_lx, regnames[rt], uimm); + if (rs != 0 && (ctx->insn_flags & ISA_MIPS32R6)) { + /* OPC_AUI */ + tcg_gen_addi_tl(cpu_gpr[rt], cpu_gpr[rs], imm << 16); + tcg_gen_ext32s_tl(cpu_gpr[rt], cpu_gpr[rt]); + MIPS_DEBUG("aui %s, %s, %04x", regnames[rt], regnames[rs], imm); + } else { + tcg_gen_movi_tl(cpu_gpr[rt], imm << 16); + MIPS_DEBUG("lui %s, " TARGET_FMT_lx, regnames[rt], uimm); + } break; default: @@ -2767,6 +2797,77 @@ static void gen_HILO(DisasContext *ctx, uint32_t opc, int acc, int reg) MIPS_DEBUG("%s %s", opn, regnames[reg]); } +static inline void gen_r6_ld(target_long addr, int reg, int memidx, + TCGMemOp memop) +{ + TCGv t0 = tcg_const_tl(addr); + tcg_gen_qemu_ld_tl(t0, t0, memidx, memop); + gen_store_gpr(t0, reg); + tcg_temp_free(t0); +} + +static inline void gen_pcrel(DisasContext *ctx, int rs, int16_t imm) +{ + target_long offset; + target_long addr; + + switch (MASK_OPC_PCREL_TOP2BITS(ctx->opcode)) { + case OPC_ADDIUPC: + if (rs != 0) { + offset = sextract32(ctx->opcode << 2, 0, 21); + addr = addr_add(ctx, ctx->pc, offset); + tcg_gen_movi_tl(cpu_gpr[rs], addr); + } + break; + case R6_OPC_LWPC: + offset = sextract32(ctx->opcode << 2, 0, 21); + addr = addr_add(ctx, ctx->pc, offset); + gen_r6_ld(addr, rs, ctx->mem_idx, MO_TESL); + break; +#if defined(TARGET_MIPS64) + case OPC_LWUPC: + check_mips_64(ctx); + offset = sextract32(ctx->opcode << 2, 0, 21); + addr = addr_add(ctx, ctx->pc, offset); + gen_r6_ld(addr, rs, ctx->mem_idx, MO_TEUL); + break; +#endif + default: + switch (MASK_OPC_PCREL_TOP5BITS(ctx->opcode)) { + case OPC_AUIPC: + if (rs != 0) { + offset = imm << 16; + addr = addr_add(ctx, ctx->pc, offset); + tcg_gen_movi_tl(cpu_gpr[rs], addr); + } + break; + case OPC_ALUIPC: + if (rs != 0) { + offset = imm << 16; + addr = ~0xFFFF & addr_add(ctx, ctx->pc, offset); + tcg_gen_movi_tl(cpu_gpr[rs], addr); + } + break; +#if defined(TARGET_MIPS64) + case R6_OPC_LDPC: /* bits 16 and 17 are part of immediate */ + case R6_OPC_LDPC + (1 << 16): + case R6_OPC_LDPC + (2 << 16): + case R6_OPC_LDPC + (3 << 16): + check_mips_64(ctx); + offset = sextract32(ctx->opcode << 3, 0, 21); + addr = addr_add(ctx, (ctx->pc & ~0x7), offset); + gen_r6_ld(addr, rs, ctx->mem_idx, MO_TEQ); + break; +#endif + default: + MIPS_INVAL("OPC_PCREL"); + generate_exception(ctx, EXCP_RI); + break; + } + break; + } +} + static void gen_r6_muldiv(DisasContext *ctx, int opc, int rd, int rs, int rt) { const char *opn = "r6 mul/div"; @@ -15097,6 +15198,20 @@ static void decode_opc_special_r6(CPUMIPSState *env, DisasContext *ctx) op1 = MASK_SPECIAL(ctx->opcode); switch (op1) { + case OPC_LSA: + if (rd != 0) { + int imm2 = extract32(ctx->opcode, 6, 3); + TCGv t0 = tcg_temp_new(); + TCGv t1 = tcg_temp_new(); + gen_load_gpr(t0, rs); + gen_load_gpr(t1, rt); + tcg_gen_shli_tl(t0, t0, imm2 + 1); + tcg_gen_add_tl(t0, t0, t1); + tcg_gen_ext32s_tl(cpu_gpr[rd], t0); + tcg_temp_free(t1); + tcg_temp_free(t0); + } + break; case OPC_MULT ... OPC_DIVU: op2 = MASK_R6_MULDIV(ctx->opcode); switch (op2) { @@ -15134,6 +15249,20 @@ static void decode_opc_special_r6(CPUMIPSState *env, DisasContext *ctx) generate_exception(ctx, EXCP_DBp); break; #if defined(TARGET_MIPS64) + case OPC_DLSA: + check_mips_64(ctx); + if (rd != 0) { + int imm2 = extract32(ctx->opcode, 6, 3); + TCGv t0 = tcg_temp_new(); + TCGv t1 = tcg_temp_new(); + gen_load_gpr(t0, rs); + gen_load_gpr(t1, rt); + tcg_gen_shli_tl(t0, t0, imm2 + 1); + tcg_gen_add_tl(cpu_gpr[rd], t0, t1); + tcg_temp_free(t1); + tcg_temp_free(t0); + } + break; case R6_OPC_DCLO: case R6_OPC_DCLZ: if (rt == 0 && sa == 1) { @@ -15319,13 +15448,18 @@ static void decode_opc_special(CPUMIPSState *env, DisasContext *ctx) case OPC_TNE: gen_trap(ctx, op1, rs, rt, -1); break; - case OPC_PMON: /* Pmon entry point, also R4010 selsl */ + case OPC_LSA: /* OPC_PMON */ + if (ctx->insn_flags & ISA_MIPS32R6) { + decode_opc_special_r6(env, ctx); + } else { + /* Pmon entry point, also R4010 selsl */ #ifdef MIPS_STRICT_STANDARD - MIPS_INVAL("PMON / selsl"); - generate_exception(ctx, EXCP_RI); + MIPS_INVAL("PMON / selsl"); + generate_exception(ctx, EXCP_RI); #else - gen_helper_0e0i(pmon, sa); + gen_helper_0e0i(pmon, sa); #endif + } break; case OPC_SYSCALL: generate_exception(ctx, EXCP_SYSCALL); @@ -16297,6 +16431,24 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx) check_dsp(ctx); gen_compute_branch(ctx, op1, 4, -1, -2, (int32_t)imm << 2); break; +#if defined(TARGET_MIPS64) + case OPC_DAHI: + check_insn(ctx, ISA_MIPS32R6); + check_mips_64(ctx); + if (rs != 0) { + tcg_gen_addi_tl(cpu_gpr[rs], cpu_gpr[rs], (int64_t)imm << 32); + } + MIPS_DEBUG("dahi %s, %04x", regnames[rs], imm); + break; + case OPC_DATI: + check_insn(ctx, ISA_MIPS32R6); + check_mips_64(ctx); + if (rs != 0) { + tcg_gen_addi_tl(cpu_gpr[rs], cpu_gpr[rs], (int64_t)imm << 48); + } + MIPS_DEBUG("dati %s, %04x", regnames[rs], imm); + break; +#endif default: /* Invalid */ MIPS_INVAL("regimm"); generate_exception(ctx, EXCP_RI); @@ -16409,7 +16561,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx) gen_slt_imm(ctx, op, rt, rs, imm); break; case OPC_ANDI: /* Arithmetic with immediate opcode */ - case OPC_LUI: + case OPC_LUI: /* OPC_AUI */ case OPC_ORI: case OPC_XORI: gen_logic_imm(ctx, op, rt, rs, imm); @@ -16707,14 +16859,37 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx) } break; #endif - case OPC_JALX: - check_insn(ctx, ASE_MIPS16 | ASE_MICROMIPS); - offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 2; - gen_compute_branch(ctx, op, 4, rs, rt, offset); + case OPC_DAUI: /* OPC_JALX */ + if (ctx->insn_flags & ISA_MIPS32R6) { +#if defined(TARGET_MIPS64) + /* OPC_DAUI */ + check_mips_64(ctx); + if (rt != 0) { + TCGv t0 = tcg_temp_new(); + gen_load_gpr(t0, rs); + tcg_gen_addi_tl(cpu_gpr[rt], t0, imm << 16); + tcg_temp_free(t0); + } + MIPS_DEBUG("daui %s, %s, %04x", regnames[rt], regnames[rs], imm); +#else + generate_exception(ctx, EXCP_RI); + MIPS_INVAL("major opcode"); +#endif + } else { + /* OPC_JALX */ + check_insn(ctx, ASE_MIPS16 | ASE_MICROMIPS); + offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 2; + gen_compute_branch(ctx, op, 4, rs, rt, offset); + } break; case OPC_MDMX: check_insn(ctx, ASE_MDMX); /* MDMX: Not implemented. */ + break; + case OPC_PCREL: + check_insn(ctx, ISA_MIPS32R6); + gen_pcrel(ctx, rs, imm); + break; default: /* Invalid */ MIPS_INVAL("major opcode"); generate_exception(ctx, EXCP_RI); From 2d31e0607d0038b0c3450bb9624b0639e1181b1a Mon Sep 17 00:00:00 2001 From: Leon Alrae Date: Fri, 27 Jun 2014 08:49:06 +0100 Subject: [PATCH 15/28] softfloat: add functions corresponding to IEEE-2008 min/maxNumMag Add abs argument to the existing softfloat minmax() function and define new float{32,64}_{min,max}nummag functions. minnummag(x,y) returns x if |x| < |y|, returns y if |y| < |x|, otherwise minnum(x,y) maxnummag(x,y) returns x if |x| > |y|, returns y if |y| > |x|, otherwise maxnum(x,y) Signed-off-by: Leon Alrae Reviewed-by: Aurelien Jarno --- fpu/softfloat.c | 37 +++++++++++++++++++++++++++++++------ include/fpu/softfloat.h | 4 ++++ 2 files changed, 35 insertions(+), 6 deletions(-) diff --git a/fpu/softfloat.c b/fpu/softfloat.c index 9274ebf101..16b21ebe61 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -7240,13 +7240,17 @@ int float128_compare_quiet( float128 a, float128 b STATUS_PARAM ) * minnum() and maxnum correspond to the IEEE 754-2008 minNum() * and maxNum() operations. min() and max() are the typical min/max * semantics provided by many CPUs which predate that specification. + * + * minnummag() and maxnummag() functions correspond to minNumMag() + * and minNumMag() from the IEEE-754 2008. */ #define MINMAX(s) \ static inline float ## s float ## s ## _minmax(float ## s a, float ## s b, \ - int ismin, int isieee STATUS_PARAM) \ + int ismin, int isieee, \ + int ismag STATUS_PARAM) \ { \ flag aSign, bSign; \ - uint ## s ## _t av, bv; \ + uint ## s ## _t av, bv, aav, abv; \ a = float ## s ## _squash_input_denormal(a STATUS_VAR); \ b = float ## s ## _squash_input_denormal(b STATUS_VAR); \ if (float ## s ## _is_any_nan(a) || \ @@ -7266,6 +7270,17 @@ static inline float ## s float ## s ## _minmax(float ## s a, float ## s b, \ bSign = extractFloat ## s ## Sign(b); \ av = float ## s ## _val(a); \ bv = float ## s ## _val(b); \ + if (ismag) { \ + aav = float ## s ## _abs(av); \ + abv = float ## s ## _abs(bv); \ + if (aav != abv) { \ + if (ismin) { \ + return (aav < abv) ? a : b; \ + } else { \ + return (aav < abv) ? b : a; \ + } \ + } \ + } \ if (aSign != bSign) { \ if (ismin) { \ return aSign ? a : b; \ @@ -7283,22 +7298,32 @@ static inline float ## s float ## s ## _minmax(float ## s a, float ## s b, \ \ float ## s float ## s ## _min(float ## s a, float ## s b STATUS_PARAM) \ { \ - return float ## s ## _minmax(a, b, 1, 0 STATUS_VAR); \ + return float ## s ## _minmax(a, b, 1, 0, 0 STATUS_VAR); \ } \ \ float ## s float ## s ## _max(float ## s a, float ## s b STATUS_PARAM) \ { \ - return float ## s ## _minmax(a, b, 0, 0 STATUS_VAR); \ + return float ## s ## _minmax(a, b, 0, 0, 0 STATUS_VAR); \ } \ \ float ## s float ## s ## _minnum(float ## s a, float ## s b STATUS_PARAM) \ { \ - return float ## s ## _minmax(a, b, 1, 1 STATUS_VAR); \ + return float ## s ## _minmax(a, b, 1, 1, 0 STATUS_VAR); \ } \ \ float ## s float ## s ## _maxnum(float ## s a, float ## s b STATUS_PARAM) \ { \ - return float ## s ## _minmax(a, b, 0, 1 STATUS_VAR); \ + return float ## s ## _minmax(a, b, 0, 1, 0 STATUS_VAR); \ +} \ + \ +float ## s float ## s ## _minnummag(float ## s a, float ## s b STATUS_PARAM) \ +{ \ + return float ## s ## _minmax(a, b, 1, 1, 1 STATUS_VAR); \ +} \ + \ +float ## s float ## s ## _maxnummag(float ## s a, float ## s b STATUS_PARAM) \ +{ \ + return float ## s ## _minmax(a, b, 0, 1, 1 STATUS_VAR); \ } MINMAX(32) diff --git a/include/fpu/softfloat.h b/include/fpu/softfloat.h index 77177c5317..e32e25d547 100644 --- a/include/fpu/softfloat.h +++ b/include/fpu/softfloat.h @@ -374,6 +374,8 @@ float32 float32_min(float32, float32 STATUS_PARAM); float32 float32_max(float32, float32 STATUS_PARAM); float32 float32_minnum(float32, float32 STATUS_PARAM); float32 float32_maxnum(float32, float32 STATUS_PARAM); +float32 float32_minnummag(float32, float32 STATUS_PARAM); +float32 float32_maxnummag(float32, float32 STATUS_PARAM); int float32_is_quiet_nan( float32 ); int float32_is_signaling_nan( float32 ); float32 float32_maybe_silence_nan( float32 ); @@ -484,6 +486,8 @@ float64 float64_min(float64, float64 STATUS_PARAM); float64 float64_max(float64, float64 STATUS_PARAM); float64 float64_minnum(float64, float64 STATUS_PARAM); float64 float64_maxnum(float64, float64 STATUS_PARAM); +float64 float64_minnummag(float64, float64 STATUS_PARAM); +float64 float64_maxnummag(float64, float64 STATUS_PARAM); int float64_is_quiet_nan( float64 a ); int float64_is_signaling_nan( float64 ); float64 float64_maybe_silence_nan( float64 ); From e7f16abbc5b4058180e14c5912ef319f222b39fc Mon Sep 17 00:00:00 2001 From: Leon Alrae Date: Fri, 27 Jun 2014 08:49:07 +0100 Subject: [PATCH 16/28] target-mips: add new Floating Point instructions In terms of encoding MIPS32R6 MIN.fmt, MAX.fmt, MINA.fmt, MAXA.fmt replaced MIPS-3D RECIP1, RECIP2, RSQRT1, RSQRT2 instructions. In R6 all Floating Point instructions are supposed to be IEEE-2008 compliant i.e. FIR.HAS2008 always 1. However, QEMU softfloat for MIPS has not been updated yet. Signed-off-by: Leon Alrae Reviewed-by: Yongbok Kim --- disas/mips.c | 22 ++ target-mips/helper.h | 20 ++ target-mips/op_helper.c | 104 +++++++++ target-mips/translate.c | 493 ++++++++++++++++++++++++++++++++++------ 4 files changed, 569 insertions(+), 70 deletions(-) diff --git a/disas/mips.c b/disas/mips.c index 850cb65dd7..fed2e5e07d 100644 --- a/disas/mips.c +++ b/disas/mips.c @@ -1263,6 +1263,28 @@ const struct mips_opcode mips_builtin_opcodes[] = {"cache", "k,o(b)", 0x7c000025, 0xfc00007f, RD_b, 0, I32R6}, {"seleqz", "d,v,t", 0x00000035, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I32R6}, {"selnez", "d,v,t", 0x00000037, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I32R6}, +{"maddf.s", "D,S,T", 0x46000018, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, I32R6}, +{"maddf.d", "D,S,T", 0x46200018, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I32R6}, +{"msubf.s", "D,S,T", 0x46000019, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, I32R6}, +{"msubf.d", "D,S,T", 0x46200019, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I32R6}, +{"max.s", "D,S,T", 0x4600001e, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, I32R6}, +{"max.d", "D,S,T", 0x4620001e, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I32R6}, +{"maxa.s", "D,S,T", 0x4600001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, I32R6}, +{"maxa.d", "D,S,T", 0x4620001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I32R6}, +{"rint.s", "D,S", 0x4600001a, 0xffff003f, WR_D|RD_S|FP_S, 0, I32R6}, +{"rint.d", "D,S", 0x4620001a, 0xffff003f, WR_D|RD_S|FP_D, 0, I32R6}, +{"class.s", "D,S", 0x4600001b, 0xffff003f, WR_D|RD_S|FP_S, 0, I32R6}, +{"class.d", "D,S", 0x4620001b, 0xffff003f, WR_D|RD_S|FP_D, 0, I32R6}, +{"min.s", "D,S,T", 0x4600001c, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, I32R6}, +{"min.d", "D,S,T", 0x4620001c, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I32R6}, +{"mina.s", "D,S,T", 0x4600001d, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, I32R6}, +{"mina.d", "D,S,T", 0x4620001d, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I32R6}, +{"sel.s", "D,S,T", 0x46000010, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, I32R6}, +{"sel.d", "D,S,T", 0x46200010, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I32R6}, +{"seleqz.s", "D,S,T", 0x46000014, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, I32R6}, +{"seleqz.d", "D,S,T", 0x46200014, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I32R6}, +{"selnez.s", "D,S,T", 0x46000017, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, I32R6}, +{"selnez.d", "D,S,T", 0x46200017, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I32R6}, {"align", "d,v,t", 0x7c000220, 0xfc00073f, WR_d|RD_s|RD_t, 0, I32R6}, {"dalign", "d,v,t", 0x7c000224, 0xfc00063f, WR_d|RD_s|RD_t, 0, I64R6}, {"bitswap", "d,w", 0x7c000020, 0xffe007ff, WR_d|RD_t, 0, I32R6}, diff --git a/target-mips/helper.h b/target-mips/helper.h index 5511dfcc3a..9020c7bd6a 100644 --- a/target-mips/helper.h +++ b/target-mips/helper.h @@ -202,6 +202,25 @@ DEF_HELPER_2(float_cvtw_d, i32, env, i64) DEF_HELPER_3(float_addr_ps, i64, env, i64, i64) DEF_HELPER_3(float_mulr_ps, i64, env, i64, i64) +DEF_HELPER_FLAGS_1(float_class_s, TCG_CALL_NO_RWG_SE, i32, i32) +DEF_HELPER_FLAGS_1(float_class_d, TCG_CALL_NO_RWG_SE, i64, i64) + +#define FOP_PROTO(op) \ +DEF_HELPER_4(float_ ## op ## _s, i32, env, i32, i32, i32) \ +DEF_HELPER_4(float_ ## op ## _d, i64, env, i64, i64, i64) +FOP_PROTO(maddf) +FOP_PROTO(msubf) +#undef FOP_PROTO + +#define FOP_PROTO(op) \ +DEF_HELPER_3(float_ ## op ## _s, i32, env, i32, i32) \ +DEF_HELPER_3(float_ ## op ## _d, i64, env, i64, i64) +FOP_PROTO(max) +FOP_PROTO(maxa) +FOP_PROTO(min) +FOP_PROTO(mina) +#undef FOP_PROTO + #define FOP_PROTO(op) \ DEF_HELPER_2(float_ ## op ## l_s, i64, env, i32) \ DEF_HELPER_2(float_ ## op ## l_d, i64, env, i64) \ @@ -219,6 +238,7 @@ DEF_HELPER_2(float_ ## op ## _d, i64, env, i64) FOP_PROTO(sqrt) FOP_PROTO(rsqrt) FOP_PROTO(recip) +FOP_PROTO(rint) #undef FOP_PROTO #define FOP_PROTO(op) \ diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index c9841e26f8..3f449ae428 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -2809,6 +2809,110 @@ FLOAT_UNOP(abs) FLOAT_UNOP(chs) #undef FLOAT_UNOP +#define FLOAT_FMADDSUB(name, bits, muladd_arg) \ +uint ## bits ## _t helper_float_ ## name (CPUMIPSState *env, \ + uint ## bits ## _t fs, \ + uint ## bits ## _t ft, \ + uint ## bits ## _t fd) \ +{ \ + uint ## bits ## _t fdret; \ + \ + fdret = float ## bits ## _muladd(fs, ft, fd, muladd_arg, \ + &env->active_fpu.fp_status); \ + update_fcr31(env, GETPC()); \ + return fdret; \ +} + +FLOAT_FMADDSUB(maddf_s, 32, 0) +FLOAT_FMADDSUB(maddf_d, 64, 0) +FLOAT_FMADDSUB(msubf_s, 32, float_muladd_negate_product) +FLOAT_FMADDSUB(msubf_d, 64, float_muladd_negate_product) +#undef FLOAT_FMADDSUB + +#define FLOAT_MINMAX(name, bits, minmaxfunc) \ +uint ## bits ## _t helper_float_ ## name (CPUMIPSState *env, \ + uint ## bits ## _t fs, \ + uint ## bits ## _t ft) \ +{ \ + uint ## bits ## _t fdret; \ + \ + fdret = float ## bits ## _ ## minmaxfunc(fs, ft, \ + &env->active_fpu.fp_status); \ + update_fcr31(env, GETPC()); \ + return fdret; \ +} + +FLOAT_MINMAX(max_s, 32, maxnum) +FLOAT_MINMAX(max_d, 64, maxnum) +FLOAT_MINMAX(maxa_s, 32, maxnummag) +FLOAT_MINMAX(maxa_d, 64, maxnummag) + +FLOAT_MINMAX(min_s, 32, minnum) +FLOAT_MINMAX(min_d, 64, minnum) +FLOAT_MINMAX(mina_s, 32, minnummag) +FLOAT_MINMAX(mina_d, 64, minnummag) +#undef FLOAT_MINMAX + +#define FLOAT_RINT(name, bits) \ +uint ## bits ## _t helper_float_ ## name (CPUMIPSState *env, \ + uint ## bits ## _t fs) \ +{ \ + uint ## bits ## _t fdret; \ + \ + fdret = float ## bits ## _round_to_int(fs, &env->active_fpu.fp_status); \ + update_fcr31(env, GETPC()); \ + return fdret; \ +} + +FLOAT_RINT(rint_s, 32) +FLOAT_RINT(rint_d, 64) +#undef FLOAT_RINT + +#define FLOAT_CLASS_SIGNALING_NAN 0x001 +#define FLOAT_CLASS_QUIET_NAN 0x002 +#define FLOAT_CLASS_NEGATIVE_INFINITY 0x004 +#define FLOAT_CLASS_NEGATIVE_NORMAL 0x008 +#define FLOAT_CLASS_NEGATIVE_SUBNORMAL 0x010 +#define FLOAT_CLASS_NEGATIVE_ZERO 0x020 +#define FLOAT_CLASS_POSITIVE_INFINITY 0x040 +#define FLOAT_CLASS_POSITIVE_NORMAL 0x080 +#define FLOAT_CLASS_POSITIVE_SUBNORMAL 0x100 +#define FLOAT_CLASS_POSITIVE_ZERO 0x200 + +#define FLOAT_CLASS(name, bits) \ +uint ## bits ## _t helper_float_ ## name (uint ## bits ## _t arg) \ +{ \ + if (float ## bits ## _is_signaling_nan(arg)) { \ + return FLOAT_CLASS_SIGNALING_NAN; \ + } else if (float ## bits ## _is_quiet_nan(arg)) { \ + return FLOAT_CLASS_QUIET_NAN; \ + } else if (float ## bits ## _is_neg(arg)) { \ + if (float ## bits ## _is_infinity(arg)) { \ + return FLOAT_CLASS_NEGATIVE_INFINITY; \ + } else if (float ## bits ## _is_zero(arg)) { \ + return FLOAT_CLASS_NEGATIVE_ZERO; \ + } else if (float ## bits ## _is_zero_or_denormal(arg)) { \ + return FLOAT_CLASS_NEGATIVE_SUBNORMAL; \ + } else { \ + return FLOAT_CLASS_NEGATIVE_NORMAL; \ + } \ + } else { \ + if (float ## bits ## _is_infinity(arg)) { \ + return FLOAT_CLASS_POSITIVE_INFINITY; \ + } else if (float ## bits ## _is_zero(arg)) { \ + return FLOAT_CLASS_POSITIVE_ZERO; \ + } else if (float ## bits ## _is_zero_or_denormal(arg)) { \ + return FLOAT_CLASS_POSITIVE_SUBNORMAL; \ + } else { \ + return FLOAT_CLASS_POSITIVE_NORMAL; \ + } \ + } \ +} + +FLOAT_CLASS(class_s, 32) +FLOAT_CLASS(class_d, 64) +#undef FLOAT_CLASS + /* MIPS specific unary operations */ uint64_t helper_float_recip_d(CPUMIPSState *env, uint64_t fdt0) { diff --git a/target-mips/translate.c b/target-mips/translate.c index 45ff5fc094..b6713b2568 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -7647,14 +7647,25 @@ enum fopcode { OPC_TRUNC_W_S = FOP(13, FMT_S), OPC_CEIL_W_S = FOP(14, FMT_S), OPC_FLOOR_W_S = FOP(15, FMT_S), + OPC_SEL_S = FOP(16, FMT_S), OPC_MOVCF_S = FOP(17, FMT_S), OPC_MOVZ_S = FOP(18, FMT_S), OPC_MOVN_S = FOP(19, FMT_S), + OPC_SELEQZ_S = FOP(20, FMT_S), OPC_RECIP_S = FOP(21, FMT_S), OPC_RSQRT_S = FOP(22, FMT_S), + OPC_SELNEZ_S = FOP(23, FMT_S), + OPC_MADDF_S = FOP(24, FMT_S), + OPC_MSUBF_S = FOP(25, FMT_S), + OPC_RINT_S = FOP(26, FMT_S), + OPC_CLASS_S = FOP(27, FMT_S), + OPC_MIN_S = FOP(28, FMT_S), OPC_RECIP2_S = FOP(28, FMT_S), + OPC_MINA_S = FOP(29, FMT_S), OPC_RECIP1_S = FOP(29, FMT_S), + OPC_MAX_S = FOP(30, FMT_S), OPC_RSQRT1_S = FOP(30, FMT_S), + OPC_MAXA_S = FOP(31, FMT_S), OPC_RSQRT2_S = FOP(31, FMT_S), OPC_CVT_D_S = FOP(33, FMT_S), OPC_CVT_W_S = FOP(36, FMT_S), @@ -7693,14 +7704,25 @@ enum fopcode { OPC_TRUNC_W_D = FOP(13, FMT_D), OPC_CEIL_W_D = FOP(14, FMT_D), OPC_FLOOR_W_D = FOP(15, FMT_D), + OPC_SEL_D = FOP(16, FMT_D), OPC_MOVCF_D = FOP(17, FMT_D), OPC_MOVZ_D = FOP(18, FMT_D), OPC_MOVN_D = FOP(19, FMT_D), + OPC_SELEQZ_D = FOP(20, FMT_D), OPC_RECIP_D = FOP(21, FMT_D), OPC_RSQRT_D = FOP(22, FMT_D), + OPC_SELNEZ_D = FOP(23, FMT_D), + OPC_MADDF_D = FOP(24, FMT_D), + OPC_MSUBF_D = FOP(25, FMT_D), + OPC_RINT_D = FOP(26, FMT_D), + OPC_CLASS_D = FOP(27, FMT_D), + OPC_MIN_D = FOP(28, FMT_D), OPC_RECIP2_D = FOP(28, FMT_D), + OPC_MINA_D = FOP(29, FMT_D), OPC_RECIP1_D = FOP(29, FMT_D), + OPC_MAX_D = FOP(30, FMT_D), OPC_RSQRT1_D = FOP(30, FMT_D), + OPC_MAXA_D = FOP(31, FMT_D), OPC_RSQRT2_D = FOP(31, FMT_D), OPC_CVT_S_D = FOP(32, FMT_D), OPC_CVT_W_D = FOP(36, FMT_D), @@ -7956,6 +7978,79 @@ static inline void gen_movcf_ps(DisasContext *ctx, int fs, int fd, gen_set_label(l2); } +static void gen_sel_s(DisasContext *ctx, enum fopcode op1, int fd, int ft, + int fs) +{ + TCGv_i32 t1 = tcg_const_i32(0); + TCGv_i32 fp0 = tcg_temp_new_i32(); + TCGv_i32 fp1 = tcg_temp_new_i32(); + TCGv_i32 fp2 = tcg_temp_new_i32(); + gen_load_fpr32(fp0, fd); + gen_load_fpr32(fp1, ft); + gen_load_fpr32(fp2, fs); + + switch (op1) { + case OPC_SEL_S: + tcg_gen_andi_i32(fp0, fp0, 1); + tcg_gen_movcond_i32(TCG_COND_NE, fp0, fp0, t1, fp1, fp2); + break; + case OPC_SELEQZ_S: + tcg_gen_andi_i32(fp1, fp1, 1); + tcg_gen_movcond_i32(TCG_COND_EQ, fp0, fp1, t1, fp2, t1); + break; + case OPC_SELNEZ_S: + tcg_gen_andi_i32(fp1, fp1, 1); + tcg_gen_movcond_i32(TCG_COND_NE, fp0, fp1, t1, fp2, t1); + break; + default: + MIPS_INVAL("gen_sel_s"); + generate_exception (ctx, EXCP_RI); + break; + } + + gen_store_fpr32(fp0, fd); + tcg_temp_free_i32(fp2); + tcg_temp_free_i32(fp1); + tcg_temp_free_i32(fp0); + tcg_temp_free_i32(t1); +} + +static void gen_sel_d(DisasContext *ctx, enum fopcode op1, int fd, int ft, + int fs) +{ + TCGv_i64 t1 = tcg_const_i64(0); + TCGv_i64 fp0 = tcg_temp_new_i64(); + TCGv_i64 fp1 = tcg_temp_new_i64(); + TCGv_i64 fp2 = tcg_temp_new_i64(); + gen_load_fpr64(ctx, fp0, fd); + gen_load_fpr64(ctx, fp1, ft); + gen_load_fpr64(ctx, fp2, fs); + + switch (op1) { + case OPC_SEL_D: + tcg_gen_andi_i64(fp0, fp0, 1); + tcg_gen_movcond_i64(TCG_COND_NE, fp0, fp0, t1, fp1, fp2); + break; + case OPC_SELEQZ_D: + tcg_gen_andi_i64(fp1, fp1, 1); + tcg_gen_movcond_i64(TCG_COND_EQ, fp0, fp1, t1, fp2, t1); + break; + case OPC_SELNEZ_D: + tcg_gen_andi_i64(fp1, fp1, 1); + tcg_gen_movcond_i64(TCG_COND_NE, fp0, fp1, t1, fp2, t1); + break; + default: + MIPS_INVAL("gen_sel_d"); + generate_exception (ctx, EXCP_RI); + break; + } + + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp2); + tcg_temp_free_i64(fp1); + tcg_temp_free_i64(fp0); + tcg_temp_free_i64(t1); +} static void gen_farith (DisasContext *ctx, enum fopcode op1, int ft, int fs, int fd, int cc) @@ -8204,6 +8299,21 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, } opn = "floor.w.s"; break; + case OPC_SEL_S: + check_insn(ctx, ISA_MIPS32R6); + gen_sel_s(ctx, op1, fd, ft, fs); + opn = "sel.s"; + break; + case OPC_SELEQZ_S: + check_insn(ctx, ISA_MIPS32R6); + gen_sel_s(ctx, op1, fd, ft, fs); + opn = "seleqz.s"; + break; + case OPC_SELNEZ_S: + check_insn(ctx, ISA_MIPS32R6); + gen_sel_s(ctx, op1, fd, ft, fs); + opn = "selnez.s"; + break; case OPC_MOVCF_S: check_insn_opc_removed(ctx, ISA_MIPS32R6); gen_movcf_s(fs, fd, (ft >> 2) & 0x7, ft & 0x1); @@ -8267,59 +8377,175 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, } opn = "rsqrt.s"; break; - case OPC_RECIP2_S: - check_cp1_64bitmode(ctx); + case OPC_MADDF_S: + check_insn(ctx, ISA_MIPS32R6); { TCGv_i32 fp0 = tcg_temp_new_i32(); TCGv_i32 fp1 = tcg_temp_new_i32(); - + TCGv_i32 fp2 = tcg_temp_new_i32(); gen_load_fpr32(fp0, fs); gen_load_fpr32(fp1, ft); - gen_helper_float_recip2_s(fp0, cpu_env, fp0, fp1); + gen_load_fpr32(fp2, fd); + gen_helper_float_maddf_s(fp2, cpu_env, fp0, fp1, fp2); + gen_store_fpr32(fp2, fd); + tcg_temp_free_i32(fp2); tcg_temp_free_i32(fp1); - gen_store_fpr32(fp0, fd); tcg_temp_free_i32(fp0); + opn = "maddf.s"; } - opn = "recip2.s"; break; - case OPC_RECIP1_S: - check_cp1_64bitmode(ctx); - { - TCGv_i32 fp0 = tcg_temp_new_i32(); - - gen_load_fpr32(fp0, fs); - gen_helper_float_recip1_s(fp0, cpu_env, fp0); - gen_store_fpr32(fp0, fd); - tcg_temp_free_i32(fp0); - } - opn = "recip1.s"; - break; - case OPC_RSQRT1_S: - check_cp1_64bitmode(ctx); - { - TCGv_i32 fp0 = tcg_temp_new_i32(); - - gen_load_fpr32(fp0, fs); - gen_helper_float_rsqrt1_s(fp0, cpu_env, fp0); - gen_store_fpr32(fp0, fd); - tcg_temp_free_i32(fp0); - } - opn = "rsqrt1.s"; - break; - case OPC_RSQRT2_S: - check_cp1_64bitmode(ctx); + case OPC_MSUBF_S: + check_insn(ctx, ISA_MIPS32R6); { TCGv_i32 fp0 = tcg_temp_new_i32(); TCGv_i32 fp1 = tcg_temp_new_i32(); - + TCGv_i32 fp2 = tcg_temp_new_i32(); gen_load_fpr32(fp0, fs); gen_load_fpr32(fp1, ft); - gen_helper_float_rsqrt2_s(fp0, cpu_env, fp0, fp1); + gen_load_fpr32(fp2, fd); + gen_helper_float_msubf_s(fp2, cpu_env, fp0, fp1, fp2); + gen_store_fpr32(fp2, fd); + tcg_temp_free_i32(fp2); tcg_temp_free_i32(fp1); + tcg_temp_free_i32(fp0); + opn = "msubf.s"; + } + break; + case OPC_RINT_S: + check_insn(ctx, ISA_MIPS32R6); + { + TCGv_i32 fp0 = tcg_temp_new_i32(); + gen_load_fpr32(fp0, fs); + gen_helper_float_rint_s(fp0, cpu_env, fp0); gen_store_fpr32(fp0, fd); tcg_temp_free_i32(fp0); + opn = "rint.s"; + } + break; + case OPC_CLASS_S: + check_insn(ctx, ISA_MIPS32R6); + { + TCGv_i32 fp0 = tcg_temp_new_i32(); + gen_load_fpr32(fp0, fs); + gen_helper_float_class_s(fp0, fp0); + gen_store_fpr32(fp0, fd); + tcg_temp_free_i32(fp0); + opn = "class.s"; + } + break; + case OPC_MIN_S: /* OPC_RECIP2_S */ + if (ctx->insn_flags & ISA_MIPS32R6) { + /* OPC_MIN_S */ + TCGv_i32 fp0 = tcg_temp_new_i32(); + TCGv_i32 fp1 = tcg_temp_new_i32(); + TCGv_i32 fp2 = tcg_temp_new_i32(); + gen_load_fpr32(fp0, fs); + gen_load_fpr32(fp1, ft); + gen_helper_float_min_s(fp2, cpu_env, fp0, fp1); + gen_store_fpr32(fp2, fd); + tcg_temp_free_i32(fp2); + tcg_temp_free_i32(fp1); + tcg_temp_free_i32(fp0); + opn = "min.s"; + } else { + /* OPC_RECIP2_S */ + check_cp1_64bitmode(ctx); + { + TCGv_i32 fp0 = tcg_temp_new_i32(); + TCGv_i32 fp1 = tcg_temp_new_i32(); + + gen_load_fpr32(fp0, fs); + gen_load_fpr32(fp1, ft); + gen_helper_float_recip2_s(fp0, cpu_env, fp0, fp1); + tcg_temp_free_i32(fp1); + gen_store_fpr32(fp0, fd); + tcg_temp_free_i32(fp0); + } + opn = "recip2.s"; + } + break; + case OPC_MINA_S: /* OPC_RECIP1_S */ + if (ctx->insn_flags & ISA_MIPS32R6) { + /* OPC_MINA_S */ + TCGv_i32 fp0 = tcg_temp_new_i32(); + TCGv_i32 fp1 = tcg_temp_new_i32(); + TCGv_i32 fp2 = tcg_temp_new_i32(); + gen_load_fpr32(fp0, fs); + gen_load_fpr32(fp1, ft); + gen_helper_float_mina_s(fp2, cpu_env, fp0, fp1); + gen_store_fpr32(fp2, fd); + tcg_temp_free_i32(fp2); + tcg_temp_free_i32(fp1); + tcg_temp_free_i32(fp0); + opn = "mina.s"; + } else { + /* OPC_RECIP1_S */ + check_cp1_64bitmode(ctx); + { + TCGv_i32 fp0 = tcg_temp_new_i32(); + + gen_load_fpr32(fp0, fs); + gen_helper_float_recip1_s(fp0, cpu_env, fp0); + gen_store_fpr32(fp0, fd); + tcg_temp_free_i32(fp0); + } + opn = "recip1.s"; + } + break; + case OPC_MAX_S: /* OPC_RSQRT1_S */ + if (ctx->insn_flags & ISA_MIPS32R6) { + /* OPC_MAX_S */ + TCGv_i32 fp0 = tcg_temp_new_i32(); + TCGv_i32 fp1 = tcg_temp_new_i32(); + gen_load_fpr32(fp0, fs); + gen_load_fpr32(fp1, ft); + gen_helper_float_max_s(fp1, cpu_env, fp0, fp1); + gen_store_fpr32(fp1, fd); + tcg_temp_free_i32(fp1); + tcg_temp_free_i32(fp0); + opn = "max.s"; + } else { + /* OPC_RSQRT1_S */ + check_cp1_64bitmode(ctx); + { + TCGv_i32 fp0 = tcg_temp_new_i32(); + + gen_load_fpr32(fp0, fs); + gen_helper_float_rsqrt1_s(fp0, cpu_env, fp0); + gen_store_fpr32(fp0, fd); + tcg_temp_free_i32(fp0); + } + opn = "rsqrt1.s"; + } + break; + case OPC_MAXA_S: /* OPC_RSQRT2_S */ + if (ctx->insn_flags & ISA_MIPS32R6) { + /* OPC_MAXA_S */ + TCGv_i32 fp0 = tcg_temp_new_i32(); + TCGv_i32 fp1 = tcg_temp_new_i32(); + gen_load_fpr32(fp0, fs); + gen_load_fpr32(fp1, ft); + gen_helper_float_maxa_s(fp1, cpu_env, fp0, fp1); + gen_store_fpr32(fp1, fd); + tcg_temp_free_i32(fp1); + tcg_temp_free_i32(fp0); + opn = "maxa.s"; + } else { + /* OPC_RSQRT2_S */ + check_cp1_64bitmode(ctx); + { + TCGv_i32 fp0 = tcg_temp_new_i32(); + TCGv_i32 fp1 = tcg_temp_new_i32(); + + gen_load_fpr32(fp0, fs); + gen_load_fpr32(fp1, ft); + gen_helper_float_rsqrt2_s(fp0, cpu_env, fp0, fp1); + tcg_temp_free_i32(fp1); + gen_store_fpr32(fp0, fd); + tcg_temp_free_i32(fp0); + } + opn = "rsqrt2.s"; } - opn = "rsqrt2.s"; break; case OPC_CVT_D_S: check_cp1_registers(ctx, fd); @@ -8618,6 +8844,21 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, } opn = "floor.w.d"; break; + case OPC_SEL_D: + check_insn(ctx, ISA_MIPS32R6); + gen_sel_d(ctx, op1, fd, ft, fs); + opn = "sel.d"; + break; + case OPC_SELEQZ_D: + check_insn(ctx, ISA_MIPS32R6); + gen_sel_d(ctx, op1, fd, ft, fs); + opn = "seleqz.d"; + break; + case OPC_SELNEZ_D: + check_insn(ctx, ISA_MIPS32R6); + gen_sel_d(ctx, op1, fd, ft, fs); + opn = "selnez.d"; + break; case OPC_MOVCF_D: check_insn_opc_removed(ctx, ISA_MIPS32R6); gen_movcf_d(ctx, fs, fd, (ft >> 2) & 0x7, ft & 0x1); @@ -8681,59 +8922,171 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, } opn = "rsqrt.d"; break; - case OPC_RECIP2_D: - check_cp1_64bitmode(ctx); + case OPC_MADDF_D: + check_insn(ctx, ISA_MIPS32R6); { TCGv_i64 fp0 = tcg_temp_new_i64(); TCGv_i64 fp1 = tcg_temp_new_i64(); - + TCGv_i64 fp2 = tcg_temp_new_i64(); gen_load_fpr64(ctx, fp0, fs); gen_load_fpr64(ctx, fp1, ft); - gen_helper_float_recip2_d(fp0, cpu_env, fp0, fp1); + gen_load_fpr64(ctx, fp2, fd); + gen_helper_float_maddf_d(fp2, cpu_env, fp0, fp1, fp2); + gen_store_fpr64(ctx, fp2, fd); + tcg_temp_free_i64(fp2); tcg_temp_free_i64(fp1); - gen_store_fpr64(ctx, fp0, fd); tcg_temp_free_i64(fp0); + opn = "maddf.d"; } - opn = "recip2.d"; break; - case OPC_RECIP1_D: - check_cp1_64bitmode(ctx); - { - TCGv_i64 fp0 = tcg_temp_new_i64(); - - gen_load_fpr64(ctx, fp0, fs); - gen_helper_float_recip1_d(fp0, cpu_env, fp0); - gen_store_fpr64(ctx, fp0, fd); - tcg_temp_free_i64(fp0); - } - opn = "recip1.d"; - break; - case OPC_RSQRT1_D: - check_cp1_64bitmode(ctx); - { - TCGv_i64 fp0 = tcg_temp_new_i64(); - - gen_load_fpr64(ctx, fp0, fs); - gen_helper_float_rsqrt1_d(fp0, cpu_env, fp0); - gen_store_fpr64(ctx, fp0, fd); - tcg_temp_free_i64(fp0); - } - opn = "rsqrt1.d"; - break; - case OPC_RSQRT2_D: - check_cp1_64bitmode(ctx); + case OPC_MSUBF_D: + check_insn(ctx, ISA_MIPS32R6); { TCGv_i64 fp0 = tcg_temp_new_i64(); TCGv_i64 fp1 = tcg_temp_new_i64(); - + TCGv_i64 fp2 = tcg_temp_new_i64(); gen_load_fpr64(ctx, fp0, fs); gen_load_fpr64(ctx, fp1, ft); - gen_helper_float_rsqrt2_d(fp0, cpu_env, fp0, fp1); + gen_load_fpr64(ctx, fp2, fd); + gen_helper_float_msubf_d(fp2, cpu_env, fp0, fp1, fp2); + gen_store_fpr64(ctx, fp2, fd); + tcg_temp_free_i64(fp2); tcg_temp_free_i64(fp1); + tcg_temp_free_i64(fp0); + opn = "msubf.d"; + } + break; + case OPC_RINT_D: + check_insn(ctx, ISA_MIPS32R6); + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + gen_load_fpr64(ctx, fp0, fs); + gen_helper_float_rint_d(fp0, cpu_env, fp0); gen_store_fpr64(ctx, fp0, fd); tcg_temp_free_i64(fp0); + opn = "rint.d"; + } + break; + case OPC_CLASS_D: + check_insn(ctx, ISA_MIPS32R6); + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + gen_load_fpr64(ctx, fp0, fs); + gen_helper_float_class_d(fp0, fp0); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + opn = "class.d"; + } + break; + case OPC_MIN_D: /* OPC_RECIP2_D */ + if (ctx->insn_flags & ISA_MIPS32R6) { + /* OPC_MIN_D */ + TCGv_i64 fp0 = tcg_temp_new_i64(); + TCGv_i64 fp1 = tcg_temp_new_i64(); + gen_load_fpr64(ctx, fp0, fs); + gen_load_fpr64(ctx, fp1, ft); + gen_helper_float_min_d(fp1, cpu_env, fp0, fp1); + gen_store_fpr64(ctx, fp1, fd); + tcg_temp_free_i64(fp1); + tcg_temp_free_i64(fp0); + opn = "min.d"; + } else { + /* OPC_RECIP2_D */ + check_cp1_64bitmode(ctx); + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + TCGv_i64 fp1 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, fs); + gen_load_fpr64(ctx, fp1, ft); + gen_helper_float_recip2_d(fp0, cpu_env, fp0, fp1); + tcg_temp_free_i64(fp1); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + } + opn = "recip2.d"; + } + break; + case OPC_MINA_D: /* OPC_RECIP1_D */ + if (ctx->insn_flags & ISA_MIPS32R6) { + /* OPC_MINA_D */ + TCGv_i64 fp0 = tcg_temp_new_i64(); + TCGv_i64 fp1 = tcg_temp_new_i64(); + gen_load_fpr64(ctx, fp0, fs); + gen_load_fpr64(ctx, fp1, ft); + gen_helper_float_mina_d(fp1, cpu_env, fp0, fp1); + gen_store_fpr64(ctx, fp1, fd); + tcg_temp_free_i64(fp1); + tcg_temp_free_i64(fp0); + opn = "mina.d"; + } else { + /* OPC_RECIP1_D */ + check_cp1_64bitmode(ctx); + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, fs); + gen_helper_float_recip1_d(fp0, cpu_env, fp0); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + } + opn = "recip1.d"; + } + break; + case OPC_MAX_D: /* OPC_RSQRT1_D */ + if (ctx->insn_flags & ISA_MIPS32R6) { + /* OPC_MAX_D */ + TCGv_i64 fp0 = tcg_temp_new_i64(); + TCGv_i64 fp1 = tcg_temp_new_i64(); + gen_load_fpr64(ctx, fp0, fs); + gen_load_fpr64(ctx, fp1, ft); + gen_helper_float_max_d(fp1, cpu_env, fp0, fp1); + gen_store_fpr64(ctx, fp1, fd); + tcg_temp_free_i64(fp1); + tcg_temp_free_i64(fp0); + opn = "max.d"; + } else { + /* OPC_RSQRT1_D */ + check_cp1_64bitmode(ctx); + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, fs); + gen_helper_float_rsqrt1_d(fp0, cpu_env, fp0); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + } + opn = "rsqrt1.d"; + } + break; + case OPC_MAXA_D: /* OPC_RSQRT2_D */ + if (ctx->insn_flags & ISA_MIPS32R6) { + /* OPC_MAXA_D */ + TCGv_i64 fp0 = tcg_temp_new_i64(); + TCGv_i64 fp1 = tcg_temp_new_i64(); + gen_load_fpr64(ctx, fp0, fs); + gen_load_fpr64(ctx, fp1, ft); + gen_helper_float_maxa_d(fp1, cpu_env, fp0, fp1); + gen_store_fpr64(ctx, fp1, fd); + tcg_temp_free_i64(fp1); + tcg_temp_free_i64(fp0); + opn = "maxa.d"; + } else { + /* OPC_RSQRT2_D */ + check_cp1_64bitmode(ctx); + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + TCGv_i64 fp1 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, fs); + gen_load_fpr64(ctx, fp1, ft); + gen_helper_float_rsqrt2_d(fp0, cpu_env, fp0, fp1); + tcg_temp_free_i64(fp1); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + } + opn = "rsqrt2.d"; } - opn = "rsqrt2.d"; break; case OPC_CMP_F_D: case OPC_CMP_UN_D: From 3f4938833c21a394bf4630c163467b401d1b3ff6 Mon Sep 17 00:00:00 2001 From: Yongbok Kim Date: Fri, 27 Jun 2014 08:49:07 +0100 Subject: [PATCH 17/28] target-mips: add new Floating Point Comparison instructions Signed-off-by: Yongbok Kim Signed-off-by: Leon Alrae Reviewed-by: Aurelien Jarno --- disas/mips.c | 44 +++++++++ target-mips/helper.h | 27 ++++++ target-mips/op_helper.c | 111 ++++++++++++++++++++++ target-mips/translate.c | 206 +++++++++++++++++++++++++++++++++++++++- 4 files changed, 386 insertions(+), 2 deletions(-) diff --git a/disas/mips.c b/disas/mips.c index fed2e5e07d..5ebb5fd6f8 100644 --- a/disas/mips.c +++ b/disas/mips.c @@ -1317,6 +1317,50 @@ const struct mips_opcode mips_builtin_opcodes[] = {"bc1nez", "T,p", 0x45a00000, 0xffe00000, CBD|RD_T|FP_S|FP_D, 0, I32R6}, {"bc2eqz", "E,p", 0x49200000, 0xffe00000, CBD|RD_C2, 0, I32R6}, {"bc2nez", "E,p", 0x49a00000, 0xffe00000, CBD|RD_C2, 0, I32R6}, +{"cmp.af.s", "D,S,T", 0x46800000, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6}, +{"cmp.un.s", "D,S,T", 0x46800001, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6}, +{"cmp.eq.s", "D,S,T", 0x46800002, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6}, +{"cmp.ueq.s", "D,S,T", 0x46800003, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6}, +{"cmp.lt.s", "D,S,T", 0x46800004, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6}, +{"cmp.ult.s", "D,S,T", 0x46800005, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6}, +{"cmp.le.s", "D,S,T", 0x46800006, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6}, +{"cmp.ule.s", "D,S,T", 0x46800007, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6}, +{"cmp.saf.s", "D,S,T", 0x46800008, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6}, +{"cmp.sun.s", "D,S,T", 0x46800009, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6}, +{"cmp.seq.s", "D,S,T", 0x4680000a, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6}, +{"cmp.sueq.s", "D,S,T", 0x4680000b, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6}, +{"cmp.slt.s", "D,S,T", 0x4680000c, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6}, +{"cmp.sult.s", "D,S,T", 0x4680000d, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6}, +{"cmp.sle.s", "D,S,T", 0x4680000e, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6}, +{"cmp.sule.s", "D,S,T", 0x4680000f, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6}, +{"cmp.or.s", "D,S,T", 0x46800011, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6}, +{"cmp.une.s", "D,S,T", 0x46800012, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6}, +{"cmp.ne.s", "D,S,T", 0x46800013, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6}, +{"cmp.sor.s", "D,S,T", 0x46800019, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6}, +{"cmp.sune.s", "D,S,T", 0x4680001a, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6}, +{"cmp.sne.s", "D,S,T", 0x4680001b, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6}, +{"cmp.af.d", "D,S,T", 0x46a00000, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6}, +{"cmp.un.d", "D,S,T", 0x46a00001, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6}, +{"cmp.eq.d", "D,S,T", 0x46a00002, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6}, +{"cmp.ueq.d", "D,S,T", 0x46a00003, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6}, +{"cmp.lt.d", "D,S,T", 0x46a00004, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6}, +{"cmp.ult.d", "D,S,T", 0x46a00005, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6}, +{"cmp.le.d", "D,S,T", 0x46a00006, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6}, +{"cmp.ule.d", "D,S,T", 0x46a00007, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6}, +{"cmp.saf.d", "D,S,T", 0x46a00008, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6}, +{"cmp.sun.d", "D,S,T", 0x46a00009, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6}, +{"cmp.seq.d", "D,S,T", 0x46a0000a, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6}, +{"cmp.sueq.d", "D,S,T", 0x46a0000b, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6}, +{"cmp.slt.d", "D,S,T", 0x46a0000c, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6}, +{"cmp.sult.d", "D,S,T", 0x46a0000d, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6}, +{"cmp.sle.d", "D,S,T", 0x46a0000e, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6}, +{"cmp.sule.d", "D,S,T", 0x46a0000f, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6}, +{"cmp.or.d", "D,S,T", 0x46a00011, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6}, +{"cmp.une.d", "D,S,T", 0x46a00012, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6}, +{"cmp.ne.d", "D,S,T", 0x46a00013, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6}, +{"cmp.sor.d", "D,S,T", 0x46a00019, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6}, +{"cmp.sune.d", "D,S,T", 0x46a0001a, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6}, +{"cmp.sne.d", "D,S,T", 0x46a0001b, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6}, {"pref", "k,o(b)", 0xcc000000, 0xfc000000, RD_b, 0, I4|I32|G3 }, {"prefx", "h,t(b)", 0x4c00000f, 0xfc0007ff, RD_b|RD_t, 0, I4|I33 }, {"nop", "", 0x00000000, 0xffffffff, 0, INSN2_ALIAS, I1 }, /* sll */ diff --git a/target-mips/helper.h b/target-mips/helper.h index 9020c7bd6a..a127db55c2 100644 --- a/target-mips/helper.h +++ b/target-mips/helper.h @@ -304,6 +304,33 @@ FOP_PROTO(le) FOP_PROTO(ngt) #undef FOP_PROTO +#define FOP_PROTO(op) \ +DEF_HELPER_3(r6_cmp_d_ ## op, i64, env, i64, i64) \ +DEF_HELPER_3(r6_cmp_s_ ## op, i32, env, i32, i32) +FOP_PROTO(af) +FOP_PROTO(un) +FOP_PROTO(eq) +FOP_PROTO(ueq) +FOP_PROTO(lt) +FOP_PROTO(ult) +FOP_PROTO(le) +FOP_PROTO(ule) +FOP_PROTO(saf) +FOP_PROTO(sun) +FOP_PROTO(seq) +FOP_PROTO(sueq) +FOP_PROTO(slt) +FOP_PROTO(sult) +FOP_PROTO(sle) +FOP_PROTO(sule) +FOP_PROTO(or) +FOP_PROTO(une) +FOP_PROTO(ne) +FOP_PROTO(sor) +FOP_PROTO(sune) +FOP_PROTO(sne) +#undef FOP_PROTO + /* Special functions */ #ifndef CONFIG_USER_ONLY DEF_HELPER_1(tlbwi, void, env) diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 3f449ae428..c48ee7f198 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -3388,3 +3388,114 @@ FOP_COND_PS(le, float32_le(fst0, fst1, &env->active_fpu.fp_status), float32_le(fsth0, fsth1, &env->active_fpu.fp_status)) FOP_COND_PS(ngt, float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || float32_le(fst0, fst1, &env->active_fpu.fp_status), float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status) || float32_le(fsth0, fsth1, &env->active_fpu.fp_status)) + +/* R6 compare operations */ +#define FOP_CONDN_D(op, cond) \ +uint64_t helper_r6_cmp_d_ ## op(CPUMIPSState * env, uint64_t fdt0, \ + uint64_t fdt1) \ +{ \ + uint64_t c; \ + c = cond; \ + update_fcr31(env, GETPC()); \ + if (c) { \ + return -1; \ + } else { \ + return 0; \ + } \ +} + +/* NOTE: the comma operator will make "cond" to eval to false, + * but float64_unordered_quiet() is still called. */ +FOP_CONDN_D(af, (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status), 0)) +FOP_CONDN_D(un, (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status))) +FOP_CONDN_D(eq, (float64_eq_quiet(fdt0, fdt1, &env->active_fpu.fp_status))) +FOP_CONDN_D(ueq, (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status) + || float64_eq_quiet(fdt0, fdt1, &env->active_fpu.fp_status))) +FOP_CONDN_D(lt, (float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status))) +FOP_CONDN_D(ult, (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status) + || float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status))) +FOP_CONDN_D(le, (float64_le_quiet(fdt0, fdt1, &env->active_fpu.fp_status))) +FOP_CONDN_D(ule, (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status) + || float64_le_quiet(fdt0, fdt1, &env->active_fpu.fp_status))) +/* NOTE: the comma operator will make "cond" to eval to false, + * but float64_unordered() is still called. */ +FOP_CONDN_D(saf, (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status), 0)) +FOP_CONDN_D(sun, (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status))) +FOP_CONDN_D(seq, (float64_eq(fdt0, fdt1, &env->active_fpu.fp_status))) +FOP_CONDN_D(sueq, (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status) + || float64_eq(fdt0, fdt1, &env->active_fpu.fp_status))) +FOP_CONDN_D(slt, (float64_lt(fdt0, fdt1, &env->active_fpu.fp_status))) +FOP_CONDN_D(sult, (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status) + || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status))) +FOP_CONDN_D(sle, (float64_le(fdt0, fdt1, &env->active_fpu.fp_status))) +FOP_CONDN_D(sule, (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status) + || float64_le(fdt0, fdt1, &env->active_fpu.fp_status))) +FOP_CONDN_D(or, (float64_le_quiet(fdt1, fdt0, &env->active_fpu.fp_status) + || float64_le_quiet(fdt0, fdt1, &env->active_fpu.fp_status))) +FOP_CONDN_D(une, (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status) + || float64_lt_quiet(fdt1, fdt0, &env->active_fpu.fp_status) + || float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status))) +FOP_CONDN_D(ne, (float64_lt_quiet(fdt1, fdt0, &env->active_fpu.fp_status) + || float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status))) +FOP_CONDN_D(sor, (float64_le(fdt1, fdt0, &env->active_fpu.fp_status) + || float64_le(fdt0, fdt1, &env->active_fpu.fp_status))) +FOP_CONDN_D(sune, (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status) + || float64_lt(fdt1, fdt0, &env->active_fpu.fp_status) + || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status))) +FOP_CONDN_D(sne, (float64_lt(fdt1, fdt0, &env->active_fpu.fp_status) + || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status))) + +#define FOP_CONDN_S(op, cond) \ +uint32_t helper_r6_cmp_s_ ## op(CPUMIPSState * env, uint32_t fst0, \ + uint32_t fst1) \ +{ \ + uint64_t c; \ + c = cond; \ + update_fcr31(env, GETPC()); \ + if (c) { \ + return -1; \ + } else { \ + return 0; \ + } \ +} + +/* NOTE: the comma operator will make "cond" to eval to false, + * but float32_unordered_quiet() is still called. */ +FOP_CONDN_S(af, (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status), 0)) +FOP_CONDN_S(un, (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status))) +FOP_CONDN_S(eq, (float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status))) +FOP_CONDN_S(ueq, (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) + || float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status))) +FOP_CONDN_S(lt, (float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status))) +FOP_CONDN_S(ult, (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) + || float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status))) +FOP_CONDN_S(le, (float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status))) +FOP_CONDN_S(ule, (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) + || float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status))) +/* NOTE: the comma operator will make "cond" to eval to false, + * but float32_unordered() is still called. */ +FOP_CONDN_S(saf, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status), 0)) +FOP_CONDN_S(sun, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status))) +FOP_CONDN_S(seq, (float32_eq(fst0, fst1, &env->active_fpu.fp_status))) +FOP_CONDN_S(sueq, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status) + || float32_eq(fst0, fst1, &env->active_fpu.fp_status))) +FOP_CONDN_S(slt, (float32_lt(fst0, fst1, &env->active_fpu.fp_status))) +FOP_CONDN_S(sult, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status) + || float32_lt(fst0, fst1, &env->active_fpu.fp_status))) +FOP_CONDN_S(sle, (float32_le(fst0, fst1, &env->active_fpu.fp_status))) +FOP_CONDN_S(sule, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status) + || float32_le(fst0, fst1, &env->active_fpu.fp_status))) +FOP_CONDN_S(or, (float32_le_quiet(fst1, fst0, &env->active_fpu.fp_status) + || float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status))) +FOP_CONDN_S(une, (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) + || float32_lt_quiet(fst1, fst0, &env->active_fpu.fp_status) + || float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status))) +FOP_CONDN_S(ne, (float32_lt_quiet(fst1, fst0, &env->active_fpu.fp_status) + || float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status))) +FOP_CONDN_S(sor, (float32_le(fst1, fst0, &env->active_fpu.fp_status) + || float32_le(fst0, fst1, &env->active_fpu.fp_status))) +FOP_CONDN_S(sune, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status) + || float32_lt(fst1, fst0, &env->active_fpu.fp_status) + || float32_lt(fst0, fst1, &env->active_fpu.fp_status))) +FOP_CONDN_S(sne, (float32_lt(fst1, fst0, &env->active_fpu.fp_status) + || float32_lt(fst0, fst1, &env->active_fpu.fp_status))) diff --git a/target-mips/translate.c b/target-mips/translate.c index b6713b2568..6f57171912 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -1622,6 +1622,98 @@ FOP_CONDS(abs, 1, s, FMT_S, 32) FOP_CONDS(, 0, ps, FMT_PS, 64) FOP_CONDS(abs, 1, ps, FMT_PS, 64) #undef FOP_CONDS + +#define FOP_CONDNS(fmt, ifmt, bits, STORE) \ +static inline void gen_r6_cmp_ ## fmt(DisasContext * ctx, int n, \ + int ft, int fs, int fd) \ +{ \ + TCGv_i ## bits fp0 = tcg_temp_new_i ## bits(); \ + TCGv_i ## bits fp1 = tcg_temp_new_i ## bits(); \ + switch (ifmt) { \ + case FMT_D: \ + check_cp1_registers(ctx, fs | ft | fd); \ + break; \ + } \ + gen_ldcmp_fpr ## bits(ctx, fp0, fs); \ + gen_ldcmp_fpr ## bits(ctx, fp1, ft); \ + switch (n) { \ + case 0: \ + gen_helper_r6_cmp_ ## fmt ## _af(fp0, cpu_env, fp0, fp1); \ + break; \ + case 1: \ + gen_helper_r6_cmp_ ## fmt ## _un(fp0, cpu_env, fp0, fp1); \ + break; \ + case 2: \ + gen_helper_r6_cmp_ ## fmt ## _eq(fp0, cpu_env, fp0, fp1); \ + break; \ + case 3: \ + gen_helper_r6_cmp_ ## fmt ## _ueq(fp0, cpu_env, fp0, fp1); \ + break; \ + case 4: \ + gen_helper_r6_cmp_ ## fmt ## _lt(fp0, cpu_env, fp0, fp1); \ + break; \ + case 5: \ + gen_helper_r6_cmp_ ## fmt ## _ult(fp0, cpu_env, fp0, fp1); \ + break; \ + case 6: \ + gen_helper_r6_cmp_ ## fmt ## _le(fp0, cpu_env, fp0, fp1); \ + break; \ + case 7: \ + gen_helper_r6_cmp_ ## fmt ## _ule(fp0, cpu_env, fp0, fp1); \ + break; \ + case 8: \ + gen_helper_r6_cmp_ ## fmt ## _saf(fp0, cpu_env, fp0, fp1); \ + break; \ + case 9: \ + gen_helper_r6_cmp_ ## fmt ## _sun(fp0, cpu_env, fp0, fp1); \ + break; \ + case 10: \ + gen_helper_r6_cmp_ ## fmt ## _seq(fp0, cpu_env, fp0, fp1); \ + break; \ + case 11: \ + gen_helper_r6_cmp_ ## fmt ## _sueq(fp0, cpu_env, fp0, fp1); \ + break; \ + case 12: \ + gen_helper_r6_cmp_ ## fmt ## _slt(fp0, cpu_env, fp0, fp1); \ + break; \ + case 13: \ + gen_helper_r6_cmp_ ## fmt ## _sult(fp0, cpu_env, fp0, fp1); \ + break; \ + case 14: \ + gen_helper_r6_cmp_ ## fmt ## _sle(fp0, cpu_env, fp0, fp1); \ + break; \ + case 15: \ + gen_helper_r6_cmp_ ## fmt ## _sule(fp0, cpu_env, fp0, fp1); \ + break; \ + case 17: \ + gen_helper_r6_cmp_ ## fmt ## _or(fp0, cpu_env, fp0, fp1); \ + break; \ + case 18: \ + gen_helper_r6_cmp_ ## fmt ## _une(fp0, cpu_env, fp0, fp1); \ + break; \ + case 19: \ + gen_helper_r6_cmp_ ## fmt ## _ne(fp0, cpu_env, fp0, fp1); \ + break; \ + case 25: \ + gen_helper_r6_cmp_ ## fmt ## _sor(fp0, cpu_env, fp0, fp1); \ + break; \ + case 26: \ + gen_helper_r6_cmp_ ## fmt ## _sune(fp0, cpu_env, fp0, fp1); \ + break; \ + case 27: \ + gen_helper_r6_cmp_ ## fmt ## _sne(fp0, cpu_env, fp0, fp1); \ + break; \ + default: \ + abort(); \ + } \ + STORE; \ + tcg_temp_free_i ## bits (fp0); \ + tcg_temp_free_i ## bits (fp1); \ +} + +FOP_CONDNS(d, FMT_D, 64, gen_store_fpr64(ctx, fp0, fd)) +FOP_CONDNS(s, FMT_S, 32, gen_store_fpr32(fp0, fd)) +#undef FOP_CONDNS #undef gen_ldcmp_fpr32 #undef gen_ldcmp_fpr64 @@ -7792,6 +7884,53 @@ enum fopcode { OPC_CMP_NGT_PS = FOP (63, FMT_PS), }; +enum r6_f_cmp_op { + R6_OPC_CMP_AF_S = FOP(0, FMT_W), + R6_OPC_CMP_UN_S = FOP(1, FMT_W), + R6_OPC_CMP_EQ_S = FOP(2, FMT_W), + R6_OPC_CMP_UEQ_S = FOP(3, FMT_W), + R6_OPC_CMP_LT_S = FOP(4, FMT_W), + R6_OPC_CMP_ULT_S = FOP(5, FMT_W), + R6_OPC_CMP_LE_S = FOP(6, FMT_W), + R6_OPC_CMP_ULE_S = FOP(7, FMT_W), + R6_OPC_CMP_SAF_S = FOP(8, FMT_W), + R6_OPC_CMP_SUN_S = FOP(9, FMT_W), + R6_OPC_CMP_SEQ_S = FOP(10, FMT_W), + R6_OPC_CMP_SEUQ_S = FOP(11, FMT_W), + R6_OPC_CMP_SLT_S = FOP(12, FMT_W), + R6_OPC_CMP_SULT_S = FOP(13, FMT_W), + R6_OPC_CMP_SLE_S = FOP(14, FMT_W), + R6_OPC_CMP_SULE_S = FOP(15, FMT_W), + R6_OPC_CMP_OR_S = FOP(17, FMT_W), + R6_OPC_CMP_UNE_S = FOP(18, FMT_W), + R6_OPC_CMP_NE_S = FOP(19, FMT_W), + R6_OPC_CMP_SOR_S = FOP(25, FMT_W), + R6_OPC_CMP_SUNE_S = FOP(26, FMT_W), + R6_OPC_CMP_SNE_S = FOP(27, FMT_W), + + R6_OPC_CMP_AF_D = FOP(0, FMT_L), + R6_OPC_CMP_UN_D = FOP(1, FMT_L), + R6_OPC_CMP_EQ_D = FOP(2, FMT_L), + R6_OPC_CMP_UEQ_D = FOP(3, FMT_L), + R6_OPC_CMP_LT_D = FOP(4, FMT_L), + R6_OPC_CMP_ULT_D = FOP(5, FMT_L), + R6_OPC_CMP_LE_D = FOP(6, FMT_L), + R6_OPC_CMP_ULE_D = FOP(7, FMT_L), + R6_OPC_CMP_SAF_D = FOP(8, FMT_L), + R6_OPC_CMP_SUN_D = FOP(9, FMT_L), + R6_OPC_CMP_SEQ_D = FOP(10, FMT_L), + R6_OPC_CMP_SEUQ_D = FOP(11, FMT_L), + R6_OPC_CMP_SLT_D = FOP(12, FMT_L), + R6_OPC_CMP_SULT_D = FOP(13, FMT_L), + R6_OPC_CMP_SLE_D = FOP(14, FMT_L), + R6_OPC_CMP_SULE_D = FOP(15, FMT_L), + R6_OPC_CMP_OR_D = FOP(17, FMT_L), + R6_OPC_CMP_UNE_D = FOP(18, FMT_L), + R6_OPC_CMP_NE_D = FOP(19, FMT_L), + R6_OPC_CMP_SOR_D = FOP(25, FMT_L), + R6_OPC_CMP_SUNE_D = FOP(26, FMT_L), + R6_OPC_CMP_SNE_D = FOP(27, FMT_L), +}; static void gen_cp1 (DisasContext *ctx, uint32_t opc, int rt, int fs) { const char *opn = "cp1 move"; @@ -17069,11 +17208,74 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx) check_insn_opc_removed(ctx, ISA_MIPS32R6); case OPC_S_FMT: case OPC_D_FMT: - case OPC_W_FMT: - case OPC_L_FMT: gen_farith(ctx, ctx->opcode & FOP(0x3f, 0x1f), rt, rd, sa, (imm >> 8) & 0x7); break; + case OPC_W_FMT: + case OPC_L_FMT: + { + int r6_op = ctx->opcode & FOP(0x3f, 0x1f); + if (ctx->insn_flags & ISA_MIPS32R6) { + switch (r6_op) { + case R6_OPC_CMP_AF_S: + case R6_OPC_CMP_UN_S: + case R6_OPC_CMP_EQ_S: + case R6_OPC_CMP_UEQ_S: + case R6_OPC_CMP_LT_S: + case R6_OPC_CMP_ULT_S: + case R6_OPC_CMP_LE_S: + case R6_OPC_CMP_ULE_S: + case R6_OPC_CMP_SAF_S: + case R6_OPC_CMP_SUN_S: + case R6_OPC_CMP_SEQ_S: + case R6_OPC_CMP_SEUQ_S: + case R6_OPC_CMP_SLT_S: + case R6_OPC_CMP_SULT_S: + case R6_OPC_CMP_SLE_S: + case R6_OPC_CMP_SULE_S: + case R6_OPC_CMP_OR_S: + case R6_OPC_CMP_UNE_S: + case R6_OPC_CMP_NE_S: + case R6_OPC_CMP_SOR_S: + case R6_OPC_CMP_SUNE_S: + case R6_OPC_CMP_SNE_S: + gen_r6_cmp_s(ctx, ctx->opcode & 0x1f, rt, rd, sa); + break; + case R6_OPC_CMP_AF_D: + case R6_OPC_CMP_UN_D: + case R6_OPC_CMP_EQ_D: + case R6_OPC_CMP_UEQ_D: + case R6_OPC_CMP_LT_D: + case R6_OPC_CMP_ULT_D: + case R6_OPC_CMP_LE_D: + case R6_OPC_CMP_ULE_D: + case R6_OPC_CMP_SAF_D: + case R6_OPC_CMP_SUN_D: + case R6_OPC_CMP_SEQ_D: + case R6_OPC_CMP_SEUQ_D: + case R6_OPC_CMP_SLT_D: + case R6_OPC_CMP_SULT_D: + case R6_OPC_CMP_SLE_D: + case R6_OPC_CMP_SULE_D: + case R6_OPC_CMP_OR_D: + case R6_OPC_CMP_UNE_D: + case R6_OPC_CMP_NE_D: + case R6_OPC_CMP_SOR_D: + case R6_OPC_CMP_SUNE_D: + case R6_OPC_CMP_SNE_D: + gen_r6_cmp_d(ctx, ctx->opcode & 0x1f, rt, rd, sa); + break; + default: + gen_farith(ctx, ctx->opcode & FOP(0x3f, 0x1f), rt, rd, sa, + (imm >> 8) & 0x7); + break; + } + } else { + gen_farith(ctx, ctx->opcode & FOP(0x3f, 0x1f), rt, rd, sa, + (imm >> 8) & 0x7); + } + break; + } default: MIPS_INVAL("cp1"); generate_exception (ctx, EXCP_RI); From ddc584bdb5375f260e7dcec3831d1bb32f665d25 Mon Sep 17 00:00:00 2001 From: Leon Alrae Date: Fri, 27 Jun 2014 08:49:07 +0100 Subject: [PATCH 18/28] target-mips: do not allow Status.FR=0 mode in 64-bit FPU Status.FR bit must be ignored on write and read as 1 when an implementation of Release 6 of the Architecture in which a 64-bit floating point unit is implemented. Signed-off-by: Leon Alrae Reviewed-by: Yongbok Kim --- target-mips/translate.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/target-mips/translate.c b/target-mips/translate.c index 6f57171912..80887812ca 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -17951,6 +17951,12 @@ void cpu_state_reset(CPUMIPSState *env) } } #endif + if ((env->insn_flags & ISA_MIPS32R6) && + (env->active_fpu.fcr0 & (1 << FCR0_F64))) { + /* Status.FR = 0 mode in 64-bit FPU not allowed in R6 */ + env->CP0_Status |= (1 << CP0St_FR); + } + compute_hflags(env); cs->exception_index = EXCP_NONE; } From 0aefa33318be6a9a6438c31921d426a755f1a2e9 Mon Sep 17 00:00:00 2001 From: Yongbok Kim Date: Fri, 27 Jun 2014 08:49:08 +0100 Subject: [PATCH 19/28] target-mips: remove JR, BLTZAL, BGEZAL and add NAL, BAL instructions Signed-off-by: Yongbok Kim Signed-off-by: Leon Alrae Reviewed-by: Aurelien Jarno --- disas/mips.c | 2 ++ target-mips/translate.c | 18 ++++++++++++++++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/disas/mips.c b/disas/mips.c index 5ebb5fd6f8..7297825138 100644 --- a/disas/mips.c +++ b/disas/mips.c @@ -1313,6 +1313,8 @@ const struct mips_opcode mips_builtin_opcodes[] = {"bgtzalc", "s,t,p", 0x1c000000, 0xffe00000, CBD|RD_s|RD_t, 0, I32R6}, {"bltzalc", "s,t,p", 0x1c000000, 0xfc000000, CBD|RD_s|RD_t, 0, I32R6}, {"bltuc", "s,t,p", 0x1c000000, 0xfc000000, CBD|RD_s|RD_t, 0, I32R6}, +{"nal", "p", 0x04100000, 0xffff0000, WR_31, 0, I32R6}, +{"bal", "p", 0x04110000, 0xffff0000, UBD|WR_31, 0, I32R6}, {"bc1eqz", "T,p", 0x45200000, 0xffe00000, CBD|RD_T|FP_S|FP_D, 0, I32R6}, {"bc1nez", "T,p", 0x45a00000, 0xffe00000, CBD|RD_T|FP_S|FP_D, 0, I32R6}, {"bc2eqz", "E,p", 0x49200000, 0xffe00000, CBD|RD_C2, 0, I32R6}, diff --git a/target-mips/translate.c b/target-mips/translate.c index 80887812ca..57c2d414d6 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -15851,6 +15851,9 @@ static void decode_opc_special_legacy(CPUMIPSState *env, DisasContext *ctx) gen_muldiv(ctx, op1, 0, rs, rt); break; #endif + case OPC_JR: + gen_compute_branch(ctx, op1, 4, rs, rd, sa); + break; case OPC_SPIM: #ifdef MIPS_STRICT_STANDARD MIPS_INVAL("SPIM"); @@ -15933,7 +15936,7 @@ static void decode_opc_special(CPUMIPSState *env, DisasContext *ctx) case OPC_XOR: gen_logic(ctx, op1, rd, rs, rt); break; - case OPC_JR ... OPC_JALR: + case OPC_JALR: gen_compute_branch(ctx, op1, 4, rs, rd, sa); break; case OPC_TGE ... OPC_TEQ: /* Traps */ @@ -16903,9 +16906,20 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx) check_insn_opc_removed(ctx, ISA_MIPS32R6); case OPC_BLTZ: case OPC_BGEZ: + gen_compute_branch(ctx, op1, 4, rs, -1, imm << 2); + break; case OPC_BLTZAL: case OPC_BGEZAL: - gen_compute_branch(ctx, op1, 4, rs, -1, imm << 2); + if (ctx->insn_flags & ISA_MIPS32R6) { + if (rs == 0) { + /* OPC_NAL, OPC_BAL */ + gen_compute_branch(ctx, op1, 4, 0, -1, imm << 2); + } else { + generate_exception(ctx, EXCP_RI); + } + } else { + gen_compute_branch(ctx, op1, 4, rs, -1, imm << 2); + } break; case OPC_TGEI ... OPC_TEQI: /* REGIMM traps */ case OPC_TNEI: From 9fba15004233950365c0273d21b3d91e8a18f97f Mon Sep 17 00:00:00 2001 From: Leon Alrae Date: Fri, 27 Jun 2014 08:49:08 +0100 Subject: [PATCH 20/28] mips_malta: update malta's pseudo-bootloader - replace JR with JALR JR has been removed in R6 and now this instruction will cause Reserved Instruction Exception. Therefore use JALR with rd=0 which is equivalent to JR. Signed-off-by: Leon Alrae Reviewed-by: Aurelien Jarno --- hw/mips/mips_malta.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/hw/mips/mips_malta.c b/hw/mips/mips_malta.c index b20807c4e4..e8e075c600 100644 --- a/hw/mips/mips_malta.c +++ b/hw/mips/mips_malta.c @@ -697,12 +697,12 @@ static void write_bootloader (CPUMIPSState *env, uint8_t *base, /* Jump to kernel code */ stl_p(p++, 0x3c1f0000 | ((kernel_entry >> 16) & 0xffff)); /* lui ra, high(kernel_entry) */ stl_p(p++, 0x37ff0000 | (kernel_entry & 0xffff)); /* ori ra, ra, low(kernel_entry) */ - stl_p(p++, 0x03e00008); /* jr ra */ + stl_p(p++, 0x03e00009); /* jalr ra */ stl_p(p++, 0x00000000); /* nop */ /* YAMON subroutines */ p = (uint32_t *) (base + 0x800); - stl_p(p++, 0x03e00008); /* jr ra */ + stl_p(p++, 0x03e00009); /* jalr ra */ stl_p(p++, 0x24020000); /* li v0,0 */ /* 808 YAMON print */ stl_p(p++, 0x03e06821); /* move t5,ra */ @@ -716,7 +716,7 @@ static void write_bootloader (CPUMIPSState *env, uint8_t *base, stl_p(p++, 0x00000000); /* nop */ stl_p(p++, 0x08000205); /* j 814 */ stl_p(p++, 0x00000000); /* nop */ - stl_p(p++, 0x01a00008); /* jr t5 */ + stl_p(p++, 0x01a00009); /* jalr t5 */ stl_p(p++, 0x01602021); /* move a0,t3 */ /* 0x83c YAMON print_count */ stl_p(p++, 0x03e06821); /* move t5,ra */ @@ -730,7 +730,7 @@ static void write_bootloader (CPUMIPSState *env, uint8_t *base, stl_p(p++, 0x258cffff); /* addiu t4,t4,-1 */ stl_p(p++, 0x1580fffa); /* bnez t4,84c */ stl_p(p++, 0x00000000); /* nop */ - stl_p(p++, 0x01a00008); /* jr t5 */ + stl_p(p++, 0x01a00009); /* jalr t5 */ stl_p(p++, 0x01602021); /* move a0,t3 */ /* 0x870 */ stl_p(p++, 0x3c08b800); /* lui t0,0xb400 */ @@ -740,7 +740,7 @@ static void write_bootloader (CPUMIPSState *env, uint8_t *base, stl_p(p++, 0x31290040); /* andi t1,t1,0x40 */ stl_p(p++, 0x1120fffc); /* beqz t1,878 */ stl_p(p++, 0x00000000); /* nop */ - stl_p(p++, 0x03e00008); /* jr ra */ + stl_p(p++, 0x03e00009); /* jalr ra */ stl_p(p++, 0xa1040000); /* sb a0,0(t0) */ } From a773cc7970432d1bad3835f3112512cabad3f367 Mon Sep 17 00:00:00 2001 From: Leon Alrae Date: Fri, 27 Jun 2014 08:49:09 +0100 Subject: [PATCH 21/28] target-mips: define a new generic CPU supporting MIPS64 Release 6 ISA Signed-off-by: Leon Alrae Reviewed-by: Yongbok Kim --- target-mips/translate_init.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/target-mips/translate_init.c b/target-mips/translate_init.c index 29dc2ef738..67b7837750 100644 --- a/target-mips/translate_init.c +++ b/target-mips/translate_init.c @@ -515,6 +515,36 @@ static const mips_def_t mips_defs[] = .insn_flags = CPU_MIPS64R2 | ASE_MIPS3D, .mmu_type = MMU_TYPE_R4000, }, + { + /* A generic CPU supporting MIPS64 Release 6 ISA. + FIXME: It does not support all the MIPS64R6 features yet. + Eventually this should be replaced by a real CPU model. */ + .name = "MIPS64R6-generic", + .CP0_PRid = 0x00010000, + .CP0_Config0 = MIPS_CONFIG0 | (0x2 << 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) | + (0 << CP0C1_PC) | (1 << CP0C1_WR) | (1 << CP0C1_EP), + .CP0_Config2 = MIPS_CONFIG2, + .CP0_Config3 = MIPS_CONFIG3, + .CP0_LLAddr_rw_bitmask = 0, + .CP0_LLAddr_shift = 0, + .SYNCI_Step = 32, + .CCRes = 2, + .CP0_Status_rw_bitmask = 0x30D8FFFF, + .CP1_fcr0 = (1 << FCR0_F64) | (1 << FCR0_L) | (1 << FCR0_W) | + (1 << FCR0_D) | (1 << FCR0_S) | (0x00 << FCR0_PRID) | + (0x0 << FCR0_REV), + .SEGBITS = 42, + /* The architectural limit is 59, but we have hardcoded 36 bit + in some places... + .PABITS = 59, */ /* the architectural limit */ + .PABITS = 36, + .insn_flags = CPU_MIPS64R6, + .mmu_type = MMU_TYPE_R4000, + }, { .name = "Loongson-2E", .CP0_PRid = 0x6302, From a83bddd60de0dfdbc04c6683c2701682073af5cf Mon Sep 17 00:00:00 2001 From: Dongxue Zhang Date: Tue, 29 Jul 2014 21:48:10 +0800 Subject: [PATCH 22/28] target-mips/translate.c: Update OPC_SYNCI Update OPC_SYNCI with BS_STOP, in order to handle the instructions which saved in the same TB of the store instruction. Signed-off-by: Dongxue Zhang Reviewed-by: Yongbok Kim [leon.alrae@imgtec.com: update microMIPS SYNCI as well] Signed-off-by: Leon Alrae --- target-mips/translate.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/target-mips/translate.c b/target-mips/translate.c index 57c2d414d6..7b9e8cd374 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -13190,6 +13190,9 @@ static void decode_micromips32_opc (CPUMIPSState *env, DisasContext *ctx, gen_logic_imm(ctx, OPC_LUI, rs, -1, imm); break; case SYNCI: + /* Break the TB to be able to sync copied instructions + immediately */ + ctx->bstate = BS_STOP; break; case BC2F: case BC2T: @@ -16928,7 +16931,9 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx) break; case OPC_SYNCI: check_insn(ctx, ISA_MIPS32R2); - /* Treat as NOP. */ + /* Break the TB to be able to sync copied instructions + immediately */ + ctx->bstate = BS_STOP; break; case OPC_BPOSGE32: /* MIPS DSP branch */ #if defined(TARGET_MIPS64) From b231c103afced2eb27af9b6a771ab4b250afb93f Mon Sep 17 00:00:00 2001 From: Yongbok Kim Date: Tue, 1 Jul 2014 17:43:05 +0100 Subject: [PATCH 23/28] target-mips: fix broken MIPS16 and microMIPS Commit 240ce26a broke MIPS16 and microMIPS support as it didn't care those branches and jumps don't have delay slot in MIPS16 and microMIPS. This patch introduces a new argument delayslot_size to the gen_compute_branch() indicating size of delay slot {0, 2, 4}. And the information is used to call handle_delay_slot() forcingly when no delay slot is required. There are some microMIPS branch and jump instructions that requires exact size of instruction in the delay slot. For indicating these instructions, MIPS_HFLAG_BDS_STRICT flag is introduced. Those fictional branch opcodes defined to support MIPS16 and microMIPS are no longer needed. Signed-off-by: Yongbok Kim Tested-by: Jonas Gorski Reviewed-by: Leon Alrae [leon.alrae@imgtec.com: cosmetic changes] Signed-off-by: Leon Alrae --- target-mips/cpu.h | 13 +- target-mips/translate.c | 300 ++++++++++++++++------------------------ 2 files changed, 124 insertions(+), 189 deletions(-) diff --git a/target-mips/cpu.h b/target-mips/cpu.h index 51a83318bd..26e7894eaf 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -431,7 +431,7 @@ struct CPUMIPSState { int error_code; uint32_t hflags; /* CPU State */ /* TMASK defines different execution modes */ -#define MIPS_HFLAG_TMASK 0xC07FF +#define MIPS_HFLAG_TMASK 0x1807FF #define MIPS_HFLAG_MODE 0x00007 /* execution modes */ /* The KSU flags must be the lowest bits in hflags. The flag order must be the same as defined for CP0 Status. This allows to use @@ -463,17 +463,18 @@ struct CPUMIPSState { #define MIPS_HFLAG_BL 0x01800 /* Likely branch */ #define MIPS_HFLAG_BR 0x02000 /* branch to register (can't link TB) */ /* Extra flags about the current pending branch. */ -#define MIPS_HFLAG_BMASK_EXT 0x3C000 +#define MIPS_HFLAG_BMASK_EXT 0x7C000 #define MIPS_HFLAG_B16 0x04000 /* branch instruction was 16 bits */ #define MIPS_HFLAG_BDS16 0x08000 /* branch requires 16-bit delay slot */ #define MIPS_HFLAG_BDS32 0x10000 /* branch requires 32-bit delay slot */ -#define MIPS_HFLAG_BX 0x20000 /* branch exchanges execution mode */ +#define MIPS_HFLAG_BDS_STRICT 0x20000 /* Strict delay slot size */ +#define MIPS_HFLAG_BX 0x40000 /* branch exchanges execution mode */ #define MIPS_HFLAG_BMASK (MIPS_HFLAG_BMASK_BASE | MIPS_HFLAG_BMASK_EXT) /* MIPS DSP resources access. */ -#define MIPS_HFLAG_DSP 0x40000 /* Enable access to MIPS DSP resources. */ -#define MIPS_HFLAG_DSPR2 0x80000 /* Enable access to MIPS DSPR2 resources. */ +#define MIPS_HFLAG_DSP 0x080000 /* Enable access to MIPS DSP resources. */ +#define MIPS_HFLAG_DSPR2 0x100000 /* Enable access to MIPS DSPR2 resources. */ /* Extra flag about HWREna register. */ -#define MIPS_HFLAG_HWRENA_ULR 0x100000 /* ULR bit from HWREna is set. */ +#define MIPS_HFLAG_HWRENA_ULR 0x200000 /* ULR bit from HWREna is set. */ target_ulong btarget; /* Jump / branch target */ target_ulong bcond; /* Branch condition (if needed) */ diff --git a/target-mips/translate.c b/target-mips/translate.c index 7b9e8cd374..8b62e66ca6 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -65,7 +65,6 @@ enum { /* Jump and branches */ OPC_J = (0x02 << 26), OPC_JAL = (0x03 << 26), - OPC_JALS = OPC_JAL | 0x5, OPC_BEQ = (0x04 << 26), /* Unconditional if rs = rt = 0 (B) */ OPC_BEQL = (0x14 << 26), OPC_BNE = (0x05 << 26), @@ -74,9 +73,8 @@ enum { OPC_BLEZL = (0x16 << 26), OPC_BGTZ = (0x07 << 26), OPC_BGTZL = (0x17 << 26), - OPC_JALX = (0x1D << 26), /* MIPS 16 only */ + OPC_JALX = (0x1D << 26), OPC_DAUI = (0x1D << 26), - OPC_JALXS = OPC_JALX | 0x5, /* Load and stores */ OPC_LDL = (0x1A << 26), OPC_LDR = (0x1B << 26), @@ -219,8 +217,6 @@ enum { /* Jumps */ OPC_JR = 0x08 | OPC_SPECIAL, /* Also JR.HB */ OPC_JALR = 0x09 | OPC_SPECIAL, /* Also JALR.HB */ - OPC_JALRC = OPC_JALR | (0x5 << 6), - OPC_JALRS = 0x10 | OPC_SPECIAL | (0x5 << 6), /* Traps */ OPC_TGE = 0x30 | OPC_SPECIAL, OPC_TGEU = 0x31 | OPC_SPECIAL, @@ -317,10 +313,8 @@ enum { OPC_BGEZ = (0x01 << 16) | OPC_REGIMM, OPC_BGEZL = (0x03 << 16) | OPC_REGIMM, OPC_BLTZAL = (0x10 << 16) | OPC_REGIMM, - OPC_BLTZALS = OPC_BLTZAL | 0x5, /* microMIPS */ OPC_BLTZALL = (0x12 << 16) | OPC_REGIMM, OPC_BGEZAL = (0x11 << 16) | OPC_REGIMM, - OPC_BGEZALS = OPC_BGEZAL | 0x5, /* microMIPS */ OPC_BGEZALL = (0x13 << 16) | OPC_REGIMM, OPC_TGEI = (0x08 << 16) | OPC_REGIMM, OPC_TGEIU = (0x09 << 16) | OPC_REGIMM, @@ -4137,7 +4131,8 @@ static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) /* Branches (before delay slot) */ static void gen_compute_branch (DisasContext *ctx, uint32_t opc, int insn_bytes, - int rs, int rt, int32_t offset) + int rs, int rt, int32_t offset, + int delayslot_size) { target_ulong btgt = -1; int blink = 0; @@ -4169,7 +4164,6 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc, break; case OPC_BGEZ: case OPC_BGEZAL: - case OPC_BGEZALS: case OPC_BGEZALL: case OPC_BGEZL: case OPC_BGTZ: @@ -4178,7 +4172,6 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc, case OPC_BLEZL: case OPC_BLTZ: case OPC_BLTZAL: - case OPC_BLTZALS: case OPC_BLTZALL: case OPC_BLTZL: /* Compare to zero */ @@ -4201,15 +4194,11 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc, case OPC_J: case OPC_JAL: case OPC_JALX: - case OPC_JALS: - case OPC_JALXS: /* Jump to immediate */ btgt = ((ctx->pc + insn_bytes) & (int32_t)0xF0000000) | (uint32_t)offset; break; case OPC_JR: case OPC_JALR: - case OPC_JALRC: - case OPC_JALRS: /* Jump to register */ if (offset != 0 && offset != 16) { /* Hint = 0 is JR/JALR, hint 16 is JR.HB/JALR.HB, the @@ -4238,12 +4227,8 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc, ctx->hflags |= MIPS_HFLAG_B; MIPS_DEBUG("balways"); break; - case OPC_BGEZALS: case OPC_BGEZAL: /* 0 >= 0 */ case OPC_BGEZALL: /* 0 >= 0 likely */ - ctx->hflags |= (opc == OPC_BGEZALS - ? MIPS_HFLAG_BDS16 - : MIPS_HFLAG_BDS32); /* Always take and link */ blink = 31; ctx->hflags |= MIPS_HFLAG_B; @@ -4255,15 +4240,11 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc, /* Treat as NOP. */ MIPS_DEBUG("bnever (NOP)"); goto out; - case OPC_BLTZALS: case OPC_BLTZAL: /* 0 < 0 */ - ctx->hflags |= (opc == OPC_BLTZALS - ? MIPS_HFLAG_BDS16 - : MIPS_HFLAG_BDS32); /* Handle as an unconditional branch to get correct delay slot checking. */ blink = 31; - btgt = ctx->pc + (opc == OPC_BLTZALS ? 6 : 8); + btgt = ctx->pc + insn_bytes + delayslot_size; ctx->hflags |= MIPS_HFLAG_B; MIPS_DEBUG("bnever and link"); break; @@ -4284,33 +4265,21 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc, ctx->hflags |= MIPS_HFLAG_B; MIPS_DEBUG("j " TARGET_FMT_lx, btgt); break; - case OPC_JALXS: case OPC_JALX: ctx->hflags |= MIPS_HFLAG_BX; /* Fallthrough */ - case OPC_JALS: case OPC_JAL: blink = 31; ctx->hflags |= MIPS_HFLAG_B; - ctx->hflags |= ((opc == OPC_JALS || opc == OPC_JALXS) - ? MIPS_HFLAG_BDS16 - : MIPS_HFLAG_BDS32); MIPS_DEBUG("jal " TARGET_FMT_lx, btgt); break; case OPC_JR: ctx->hflags |= MIPS_HFLAG_BR; - if (insn_bytes == 4) - ctx->hflags |= MIPS_HFLAG_BDS32; MIPS_DEBUG("jr %s", regnames[rs]); break; - case OPC_JALRS: case OPC_JALR: - case OPC_JALRC: blink = rt; ctx->hflags |= MIPS_HFLAG_BR; - ctx->hflags |= (opc == OPC_JALRS - ? MIPS_HFLAG_BDS16 - : MIPS_HFLAG_BDS32); MIPS_DEBUG("jalr %s, %s", regnames[rt], regnames[rs]); break; default: @@ -4348,11 +4317,7 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc, tcg_gen_setcondi_tl(TCG_COND_GE, bcond, t0, 0); MIPS_DEBUG("bgezl %s, " TARGET_FMT_lx, regnames[rs], btgt); goto likely; - case OPC_BGEZALS: case OPC_BGEZAL: - ctx->hflags |= (opc == OPC_BGEZALS - ? MIPS_HFLAG_BDS16 - : MIPS_HFLAG_BDS32); tcg_gen_setcondi_tl(TCG_COND_GE, bcond, t0, 0); MIPS_DEBUG("bgezal %s, " TARGET_FMT_lx, regnames[rs], btgt); blink = 31; @@ -4396,11 +4361,7 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc, MIPS_DEBUG("bposge64 " TARGET_FMT_lx, btgt); goto not_likely; #endif - case OPC_BLTZALS: case OPC_BLTZAL: - ctx->hflags |= (opc == OPC_BLTZALS - ? MIPS_HFLAG_BDS16 - : MIPS_HFLAG_BDS32); tcg_gen_setcondi_tl(TCG_COND_LT, bcond, t0, 0); blink = 31; MIPS_DEBUG("bltzal %s, " TARGET_FMT_lx, regnames[rs], btgt); @@ -4424,12 +4385,19 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc, blink, ctx->hflags, btgt); ctx->btarget = btgt; - if (blink > 0) { - int post_delay = insn_bytes; - int lowbit = !!(ctx->hflags & MIPS_HFLAG_M16); - if (opc != OPC_JALRC) - post_delay += ((ctx->hflags & MIPS_HFLAG_BDS16) ? 2 : 4); + switch (delayslot_size) { + case 2: + ctx->hflags |= MIPS_HFLAG_BDS16; + break; + case 4: + ctx->hflags |= MIPS_HFLAG_BDS32; + break; + } + + if (blink > 0) { + int post_delay = insn_bytes + delayslot_size; + int lowbit = !!(ctx->hflags & MIPS_HFLAG_M16); tcg_gen_movi_tl(cpu_gpr[blink], ctx->pc + post_delay + lowbit); } @@ -7664,7 +7632,7 @@ static void gen_compute_branch1(DisasContext *ctx, uint32_t op, MIPS_DEBUG("%s: cond %02x target " TARGET_FMT_lx, opn, ctx->hflags, btarget); ctx->btarget = btarget; - + ctx->hflags |= MIPS_HFLAG_BDS32; out: tcg_temp_free_i32(t0); } @@ -10666,15 +10634,15 @@ static int decode_extended_mips16_opc (CPUMIPSState *env, DisasContext *ctx) gen_addiupc(ctx, rx, imm, 0, 1); break; case M16_OPC_B: - gen_compute_branch(ctx, OPC_BEQ, 4, 0, 0, offset << 1); + gen_compute_branch(ctx, OPC_BEQ, 4, 0, 0, offset << 1, 0); /* No delay slot, so just process as a normal instruction */ break; case M16_OPC_BEQZ: - gen_compute_branch(ctx, OPC_BEQ, 4, rx, 0, offset << 1); + gen_compute_branch(ctx, OPC_BEQ, 4, rx, 0, offset << 1, 0); /* No delay slot, so just process as a normal instruction */ break; case M16_OPC_BNEQZ: - gen_compute_branch(ctx, OPC_BNE, 4, rx, 0, offset << 1); + gen_compute_branch(ctx, OPC_BNE, 4, rx, 0, offset << 1, 0); /* No delay slot, so just process as a normal instruction */ break; case M16_OPC_SHIFT: @@ -10732,10 +10700,10 @@ static int decode_extended_mips16_opc (CPUMIPSState *env, DisasContext *ctx) case M16_OPC_I8: switch (funct) { case I8_BTEQZ: - gen_compute_branch(ctx, OPC_BEQ, 4, 24, 0, offset << 1); + gen_compute_branch(ctx, OPC_BEQ, 4, 24, 0, offset << 1, 0); break; case I8_BTNEZ: - gen_compute_branch(ctx, OPC_BNE, 4, 24, 0, offset << 1); + gen_compute_branch(ctx, OPC_BNE, 4, 24, 0, offset << 1, 0); break; case I8_SWRASP: gen_st(ctx, OPC_SW, 31, 29, imm); @@ -10863,7 +10831,7 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx) case M16_OPC_B: offset = (ctx->opcode & 0x7ff) << 1; offset = (int16_t)(offset << 4) >> 4; - gen_compute_branch(ctx, OPC_BEQ, 2, 0, 0, offset); + gen_compute_branch(ctx, OPC_BEQ, 2, 0, 0, offset, 0); /* No delay slot, so just process as a normal instruction */ break; case M16_OPC_JAL: @@ -10871,16 +10839,18 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx) offset = (((ctx->opcode & 0x1f) << 21) | ((ctx->opcode >> 5) & 0x1f) << 16 | offset) << 2; - op = ((ctx->opcode >> 10) & 0x1) ? OPC_JALXS : OPC_JALS; - gen_compute_branch(ctx, op, 4, rx, ry, offset); + op = ((ctx->opcode >> 10) & 0x1) ? OPC_JALX : OPC_JAL; + gen_compute_branch(ctx, op, 4, rx, ry, offset, 2); n_bytes = 4; break; case M16_OPC_BEQZ: - gen_compute_branch(ctx, OPC_BEQ, 2, rx, 0, ((int8_t)ctx->opcode) << 1); + gen_compute_branch(ctx, OPC_BEQ, 2, rx, 0, + ((int8_t)ctx->opcode) << 1, 0); /* No delay slot, so just process as a normal instruction */ break; case M16_OPC_BNEQZ: - gen_compute_branch(ctx, OPC_BNE, 2, rx, 0, ((int8_t)ctx->opcode) << 1); + gen_compute_branch(ctx, OPC_BNE, 2, rx, 0, + ((int8_t)ctx->opcode) << 1, 0); /* No delay slot, so just process as a normal instruction */ break; case M16_OPC_SHIFT: @@ -10953,11 +10923,11 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx) switch (funct) { case I8_BTEQZ: gen_compute_branch(ctx, OPC_BEQ, 2, 24, 0, - ((int8_t)ctx->opcode) << 1); + ((int8_t)ctx->opcode) << 1, 0); break; case I8_BTNEZ: gen_compute_branch(ctx, OPC_BNE, 2, 24, 0, - ((int8_t)ctx->opcode) << 1); + ((int8_t)ctx->opcode) << 1, 0); break; case I8_SWRASP: gen_st(ctx, OPC_SW, 31, 29, (ctx->opcode & 0xff) << 2); @@ -11106,12 +11076,13 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx) int ra = (ctx->opcode >> 5) & 0x1; if (link) { - op = nd ? OPC_JALRC : OPC_JALRS; + op = OPC_JALR; } else { op = OPC_JR; } - gen_compute_branch(ctx, op, 2, ra ? 31 : rx, 31, 0); + gen_compute_branch(ctx, op, 2, ra ? 31 : rx, 31, 0, + (nd ? 0 : 2)); } break; case RR_SDBBP: @@ -11869,7 +11840,6 @@ static void gen_pool16c_insn(DisasContext *ctx) { int rd = mmreg((ctx->opcode >> 3) & 0x7); int rs = mmreg(ctx->opcode & 0x7); - int opc; switch (((ctx->opcode) >> 4) & 0x3f) { case NOT16 + 0: @@ -11925,32 +11895,27 @@ static void gen_pool16c_insn(DisasContext *ctx) { int reg = ctx->opcode & 0x1f; - gen_compute_branch(ctx, OPC_JR, 2, reg, 0, 0); + gen_compute_branch(ctx, OPC_JR, 2, reg, 0, 0, 4); } break; case JRC16 + 0: case JRC16 + 1: { int reg = ctx->opcode & 0x1f; - - gen_compute_branch(ctx, OPC_JR, 2, reg, 0, 0); + gen_compute_branch(ctx, OPC_JR, 2, reg, 0, 0, 0); /* Let normal delay slot handling in our caller take us to the branch target. */ } break; case JALR16 + 0: case JALR16 + 1: - opc = OPC_JALR; - goto do_jalr; + gen_compute_branch(ctx, OPC_JALR, 2, ctx->opcode & 0x1f, 31, 0, 4); + ctx->hflags |= MIPS_HFLAG_BDS_STRICT; + break; case JALR16S + 0: case JALR16S + 1: - opc = OPC_JALRS; - do_jalr: - { - int reg = ctx->opcode & 0x1f; - - gen_compute_branch(ctx, opc, 2, reg, 31, 0); - } + gen_compute_branch(ctx, OPC_JALR, 2, ctx->opcode & 0x1f, 31, 0, 2); + ctx->hflags |= MIPS_HFLAG_BDS_STRICT; break; case MFHI16 + 0: case MFHI16 + 1: @@ -11978,8 +11943,7 @@ static void gen_pool16c_insn(DisasContext *ctx) case JRADDIUSP + 1: { int imm = ZIMM(ctx->opcode, 0, 5); - - gen_compute_branch(ctx, OPC_JR, 2, 31, 0, 0); + gen_compute_branch(ctx, OPC_JR, 2, 31, 0, 0, 0); gen_arith_imm(ctx, OPC_ADDIU, 29, 29, imm << 2); /* Let normal delay slot handling in our caller take us to the branch target. */ @@ -12236,11 +12200,13 @@ static void gen_pool32axf (CPUMIPSState *env, DisasContext *ctx, int rt, int rs) switch (minor) { case JALR: case JALR_HB: - gen_compute_branch (ctx, OPC_JALR, 4, rs, rt, 0); + gen_compute_branch(ctx, OPC_JALR, 4, rs, rt, 0, 4); + ctx->hflags |= MIPS_HFLAG_BDS_STRICT; break; case JALRS: case JALRS_HB: - gen_compute_branch (ctx, OPC_JALRS, 4, rs, rt, 0); + gen_compute_branch(ctx, OPC_JALR, 4, rs, rt, 0, 2); + ctx->hflags |= MIPS_HFLAG_BDS_STRICT; break; default: goto pool32axf_invalid; @@ -13130,30 +13096,32 @@ static void decode_micromips32_opc (CPUMIPSState *env, DisasContext *ctx, minor = (ctx->opcode >> 21) & 0x1f; switch (minor) { case BLTZ: - mips32_op = OPC_BLTZ; - goto do_branch; + gen_compute_branch(ctx, OPC_BLTZ, 4, rs, -1, imm << 1, 4); + break; case BLTZAL: - mips32_op = OPC_BLTZAL; - goto do_branch; + gen_compute_branch(ctx, OPC_BLTZAL, 4, rs, -1, imm << 1, 4); + ctx->hflags |= MIPS_HFLAG_BDS_STRICT; + break; case BLTZALS: - mips32_op = OPC_BLTZALS; - goto do_branch; + gen_compute_branch(ctx, OPC_BLTZAL, 4, rs, -1, imm << 1, 2); + ctx->hflags |= MIPS_HFLAG_BDS_STRICT; + break; case BGEZ: - mips32_op = OPC_BGEZ; - goto do_branch; + gen_compute_branch(ctx, OPC_BGEZ, 4, rs, -1, imm << 1, 4); + break; case BGEZAL: - mips32_op = OPC_BGEZAL; - goto do_branch; + gen_compute_branch(ctx, OPC_BGEZAL, 4, rs, -1, imm << 1, 4); + ctx->hflags |= MIPS_HFLAG_BDS_STRICT; + break; case BGEZALS: - mips32_op = OPC_BGEZALS; - goto do_branch; + gen_compute_branch(ctx, OPC_BGEZAL, 4, rs, -1, imm << 1, 2); + ctx->hflags |= MIPS_HFLAG_BDS_STRICT; + break; case BLEZ: - mips32_op = OPC_BLEZ; - goto do_branch; + gen_compute_branch(ctx, OPC_BLEZ, 4, rs, -1, imm << 1, 4); + break; case BGTZ: - mips32_op = OPC_BGTZ; - do_branch: - gen_compute_branch(ctx, mips32_op, 4, rs, -1, imm << 1); + gen_compute_branch(ctx, OPC_BGTZ, 4, rs, -1, imm << 1, 4); break; /* Traps */ @@ -13181,7 +13149,7 @@ static void decode_micromips32_opc (CPUMIPSState *env, DisasContext *ctx, case BNEZC: case BEQZC: gen_compute_branch(ctx, minor == BNEZC ? OPC_BNE : OPC_BEQ, - 4, rs, 0, imm << 1); + 4, rs, 0, imm << 1, 0); /* Compact branches don't have a delay slot, so just let the normal delay slot handling take us to the branch target. */ @@ -13322,25 +13290,28 @@ static void decode_micromips32_opc (CPUMIPSState *env, DisasContext *ctx, break; case JALX32: offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 2; - gen_compute_branch(ctx, OPC_JALX, 4, rt, rs, offset); + gen_compute_branch(ctx, OPC_JALX, 4, rt, rs, offset, 4); + ctx->hflags |= MIPS_HFLAG_BDS_STRICT; break; case JALS32: offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 1; - gen_compute_branch(ctx, OPC_JALS, 4, rt, rs, offset); + gen_compute_branch(ctx, OPC_JAL, 4, rt, rs, offset, 2); + ctx->hflags |= MIPS_HFLAG_BDS_STRICT; break; case BEQ32: - gen_compute_branch(ctx, OPC_BEQ, 4, rt, rs, imm << 1); + gen_compute_branch(ctx, OPC_BEQ, 4, rt, rs, imm << 1, 4); break; case BNE32: - gen_compute_branch(ctx, OPC_BNE, 4, rt, rs, imm << 1); + gen_compute_branch(ctx, OPC_BNE, 4, rt, rs, imm << 1, 4); break; case J32: gen_compute_branch(ctx, OPC_J, 4, rt, rs, - (int32_t)(ctx->opcode & 0x3FFFFFF) << 1); + (int32_t)(ctx->opcode & 0x3FFFFFF) << 1, 4); break; case JAL32: gen_compute_branch(ctx, OPC_JAL, 4, rt, rs, - (int32_t)(ctx->opcode & 0x3FFFFFF) << 1); + (int32_t)(ctx->opcode & 0x3FFFFFF) << 1, 4); + ctx->hflags |= MIPS_HFLAG_BDS_STRICT; break; /* Floating point (COP1) */ case LWC132: @@ -13424,84 +13395,41 @@ static int decode_micromips_opc (CPUMIPSState *env, DisasContext *ctx) op = (ctx->opcode >> 10) & 0x3f; /* Enforce properly-sized instructions in a delay slot */ - if (ctx->hflags & MIPS_HFLAG_BMASK) { - int bits = ctx->hflags & MIPS_HFLAG_BMASK_EXT; - - switch (op) { - case POOL32A: - case POOL32B: - case POOL32I: - case POOL32C: - case ADDI32: - case ADDIU32: - case ORI32: - case XORI32: - case SLTI32: - case SLTIU32: - case ANDI32: - case JALX32: - case LBU32: - case LHU32: - case POOL32F: - case JALS32: - case BEQ32: - case BNE32: - case J32: - case JAL32: - case SB32: - case SH32: - case POOL32S: - case ADDIUPC: - case SWC132: - case SDC132: - case SD32: - case SW32: - case LB32: - case LH32: - case DADDIU32: - case LWC132: - case LDC132: - case LD32: - case LW32: - if (bits & MIPS_HFLAG_BDS16) { + if (ctx->hflags & MIPS_HFLAG_BDS_STRICT) { + switch (op & 0x7) { /* MSB-3..MSB-5 */ + case 0: + /* POOL32A, POOL32B, POOL32I, POOL32C */ + case 4: + /* ADDI32, ADDIU32, ORI32, XORI32, SLTI32, SLTIU32, ANDI32, JALX32 */ + case 5: + /* LBU32, LHU32, POOL32F, JALS32, BEQ32, BNE32, J32, JAL32 */ + case 6: + /* SB32, SH32, ADDIUPC, SWC132, SDC132, SW32 */ + case 7: + /* LB32, LH32, LWC132, LDC132, LW32 */ + if (ctx->hflags & MIPS_HFLAG_BDS16) { generate_exception(ctx, EXCP_RI); /* Just stop translation; the user is confused. */ ctx->bstate = BS_STOP; return 2; } break; - case POOL16A: - case POOL16B: - case POOL16C: - case LWGP16: - case POOL16F: - case LBU16: - case LHU16: - case LWSP16: - case LW16: - case SB16: - case SH16: - case SWSP16: - case SW16: - case MOVE16: - case ANDI16: - case POOL16D: - case POOL16E: - case BEQZ16: - case BNEZ16: - case B16: - case LI16: - if (bits & MIPS_HFLAG_BDS32) { + case 1: + /* POOL16A, POOL16B, POOL16C, LWGP16, POOL16F */ + case 2: + /* LBU16, LHU16, LWSP16, LW16, SB16, SH16, SWSP16, SW16 */ + case 3: + /* MOVE16, ANDI16, POOL16D, POOL16E, BEQZ16, BNEZ16, B16, LI16 */ + if (ctx->hflags & MIPS_HFLAG_BDS32) { generate_exception(ctx, EXCP_RI); /* Just stop translation; the user is confused. */ ctx->bstate = BS_STOP; return 2; } break; - default: - break; } } + switch (op) { case POOL16A: { @@ -13682,13 +13610,13 @@ static int decode_micromips_opc (CPUMIPSState *env, DisasContext *ctx) break; case B16: gen_compute_branch(ctx, OPC_BEQ, 2, 0, 0, - SIMM(ctx->opcode, 0, 10) << 1); + SIMM(ctx->opcode, 0, 10) << 1, 4); break; case BNEZ16: case BEQZ16: gen_compute_branch(ctx, op == BNEZ16 ? OPC_BNE : OPC_BEQ, 2, mmreg(uMIPS_RD(ctx->opcode)), - 0, SIMM(ctx->opcode, 0, 7) << 1); + 0, SIMM(ctx->opcode, 0, 7) << 1, 4); break; case LI16: { @@ -15855,7 +15783,7 @@ static void decode_opc_special_legacy(CPUMIPSState *env, DisasContext *ctx) break; #endif case OPC_JR: - gen_compute_branch(ctx, op1, 4, rs, rd, sa); + gen_compute_branch(ctx, op1, 4, rs, rd, sa, 4); break; case OPC_SPIM: #ifdef MIPS_STRICT_STANDARD @@ -15940,7 +15868,7 @@ static void decode_opc_special(CPUMIPSState *env, DisasContext *ctx) gen_logic(ctx, op1, rd, rs, rt); break; case OPC_JALR: - gen_compute_branch(ctx, op1, 4, rs, rd, sa); + gen_compute_branch(ctx, op1, 4, rs, rd, sa, 4); break; case OPC_TGE ... OPC_TEQ: /* Traps */ case OPC_TNE: @@ -16909,19 +16837,19 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx) check_insn_opc_removed(ctx, ISA_MIPS32R6); case OPC_BLTZ: case OPC_BGEZ: - gen_compute_branch(ctx, op1, 4, rs, -1, imm << 2); + gen_compute_branch(ctx, op1, 4, rs, -1, imm << 2, 4); break; case OPC_BLTZAL: case OPC_BGEZAL: if (ctx->insn_flags & ISA_MIPS32R6) { if (rs == 0) { /* OPC_NAL, OPC_BAL */ - gen_compute_branch(ctx, op1, 4, 0, -1, imm << 2); + gen_compute_branch(ctx, op1, 4, 0, -1, imm << 2, 4); } else { generate_exception(ctx, EXCP_RI); } } else { - gen_compute_branch(ctx, op1, 4, rs, -1, imm << 2); + gen_compute_branch(ctx, op1, 4, rs, -1, imm << 2, 4); } break; case OPC_TGEI ... OPC_TEQI: /* REGIMM traps */ @@ -16940,7 +16868,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx) case OPC_BPOSGE64: #endif check_dsp(ctx); - gen_compute_branch(ctx, op1, 4, -1, -2, (int32_t)imm << 2); + gen_compute_branch(ctx, op1, 4, -1, -2, (int32_t)imm << 2, 4); break; #if defined(TARGET_MIPS64) case OPC_DAHI: @@ -17079,7 +17007,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx) break; case OPC_J ... OPC_JAL: /* Jump */ offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 2; - gen_compute_branch(ctx, op, 4, rs, rt, offset); + gen_compute_branch(ctx, op, 4, rs, rt, offset, 4); break; /* Branch */ case OPC_BLEZC: /* OPC_BGEZC, OPC_BGEC, OPC_BLEZL */ @@ -17092,7 +17020,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx) gen_compute_compact_branch(ctx, op, rs, rt, imm << 2); } else { /* OPC_BLEZL */ - gen_compute_branch(ctx, op, 4, rs, rt, imm << 2); + gen_compute_branch(ctx, op, 4, rs, rt, imm << 2, 4); } break; case OPC_BGTZC: /* OPC_BLTZC, OPC_BLTC, OPC_BGTZL */ @@ -17105,13 +17033,13 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx) gen_compute_compact_branch(ctx, op, rs, rt, imm << 2); } else { /* OPC_BGTZL */ - gen_compute_branch(ctx, op, 4, rs, rt, imm << 2); + gen_compute_branch(ctx, op, 4, rs, rt, imm << 2, 4); } break; case OPC_BLEZALC: /* OPC_BGEZALC, OPC_BGEUC, OPC_BLEZ */ if (rt == 0) { /* OPC_BLEZ */ - gen_compute_branch(ctx, op, 4, rs, rt, imm << 2); + gen_compute_branch(ctx, op, 4, rs, rt, imm << 2, 4); } else { check_insn(ctx, ISA_MIPS32R6); /* OPC_BLEZALC, OPC_BGEZALC, OPC_BGEUC */ @@ -17121,7 +17049,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx) case OPC_BGTZALC: /* OPC_BLTZALC, OPC_BLTUC, OPC_BGTZ */ if (rt == 0) { /* OPC_BGTZ */ - gen_compute_branch(ctx, op, 4, rs, rt, imm << 2); + gen_compute_branch(ctx, op, 4, rs, rt, imm << 2, 4); } else { check_insn(ctx, ISA_MIPS32R6); /* OPC_BGTZALC, OPC_BLTZALC, OPC_BLTUC */ @@ -17133,7 +17061,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx) check_insn_opc_removed(ctx, ISA_MIPS32R6); case OPC_BEQ: case OPC_BNE: - gen_compute_branch(ctx, op, 4, rs, rt, imm << 2); + gen_compute_branch(ctx, op, 4, rs, rt, imm << 2, 4); break; case OPC_LWL: /* Load and stores */ case OPC_LWR: @@ -17453,7 +17381,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx) /* OPC_JALX */ check_insn(ctx, ASE_MIPS16 | ASE_MICROMIPS); offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 2; - gen_compute_branch(ctx, op, 4, rs, rt, offset); + gen_compute_branch(ctx, op, 4, rs, rt, offset, 4); } break; case OPC_MDMX: @@ -17562,6 +17490,12 @@ gen_intermediate_code_internal(MIPSCPU *cpu, TranslationBlock *tb, break; } + if (ctx.hflags & MIPS_HFLAG_BMASK) { + if (!(ctx.hflags & (MIPS_HFLAG_BDS16 | MIPS_HFLAG_BDS32))) { + is_delay = 1; + /* force to generate branch as no delay slot is required */ + } + } if (is_delay) { gen_branch(&ctx, insn_bytes); } From 3414e93eb7fcc8d24500edbeddf94b1bd75ac46b Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Sun, 14 Sep 2014 20:45:37 +0100 Subject: [PATCH 24/28] target-mips/dsp_helper.c: Remove unused function get_DSPControl_24() The function get_DSPControl_24() is unused; remove it. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Signed-off-by: Leon Alrae --- target-mips/dsp_helper.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/target-mips/dsp_helper.c b/target-mips/dsp_helper.c index 94083fb424..2ea94a73ba 100644 --- a/target-mips/dsp_helper.c +++ b/target-mips/dsp_helper.c @@ -76,15 +76,6 @@ static inline void set_DSPControl_24(uint32_t flag, int len, CPUMIPSState *env) env->active_tc.DSPControl |= (target_ulong)flag << 24; } -static inline uint32_t get_DSPControl_24(int len, CPUMIPSState *env) -{ - uint32_t filter; - - filter = (0x01 << len) - 1; - - return (env->active_tc.DSPControl >> 24) & filter; -} - static inline void set_DSPControl_pos(uint32_t pos, CPUMIPSState *env) { target_ulong dspc; From b808a1a812a15b91ccea3a10eea195da65909c5f Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Sun, 14 Sep 2014 20:45:38 +0100 Subject: [PATCH 25/28] target-mips/op_helper.c: Remove unused do_lbu() function The do_lbu() function defined by the expansion of HELPER_LD() is never used, so don't define it. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Signed-off-by: Leon Alrae --- target-mips/op_helper.c | 1 - 1 file changed, 1 deletion(-) diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index c48ee7f198..5204ed87ca 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -90,7 +90,6 @@ static inline type do_##name(CPUMIPSState *env, target_ulong addr, \ } \ } #endif -HELPER_LD(lbu, ldub, uint8_t) HELPER_LD(lw, ldl, int32_t) #ifdef TARGET_MIPS64 HELPER_LD(ld, ldq, int64_t) From c7986fd6cd766d95496805a75397c855cb7845af Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Sun, 14 Sep 2014 20:45:35 +0100 Subject: [PATCH 26/28] target-mips/translate.c: Add ifdef guard around check_mips64() The function check_mips64() is only used if TARGET_MIPS64 is defined; add an ifdef guard to its definition to avoid warnings about it being unused in other configurations. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Signed-off-by: Leon Alrae --- target-mips/translate.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/target-mips/translate.c b/target-mips/translate.c index 8b62e66ca6..c23cb94538 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -1548,6 +1548,7 @@ static inline void check_insn_opc_removed(DisasContext *ctx, int flags) } } +#ifdef TARGET_MIPS64 /* This code generates a "reserved instruction" exception if 64-bit instructions are not enabled. */ static inline void check_mips_64(DisasContext *ctx) @@ -1555,6 +1556,7 @@ static inline void check_mips_64(DisasContext *ctx) if (unlikely(!(ctx->hflags & MIPS_HFLAG_64))) generate_exception(ctx, EXCP_RI); } +#endif /* Define small wrappers for gen_load_fpr* so that we have a uniform calling interface for 32 and 64-bit FPRs. No sense in changing From 31efecccce53ead3197ce42c408033c5689499bb Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Sun, 14 Sep 2014 20:45:36 +0100 Subject: [PATCH 27/28] target-mips/dsp_helper.c: Add ifdef guards around various functions Add ifdef TARGET_MIPS64 guards around various functions that are only called from helpers for TARGET_MIPS64 CPUs; this avoids compiler warnings when building other configs. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Signed-off-by: Leon Alrae --- target-mips/dsp_helper.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/target-mips/dsp_helper.c b/target-mips/dsp_helper.c index 2ea94a73ba..349f2a0033 100644 --- a/target-mips/dsp_helper.c +++ b/target-mips/dsp_helper.c @@ -274,6 +274,7 @@ static inline int32_t mipsdsp_sat32_acc_q31(int32_t acc, int32_t a, return result; } +#ifdef TARGET_MIPS64 /* a[0] is LO, a[1] is HI. */ static inline void mipsdsp_sat64_acc_add_q63(int64_t *ret, int32_t ac, @@ -327,6 +328,7 @@ static inline void mipsdsp_sat64_acc_sub_q63(int64_t *ret, set_DSPControl_overflow_flag(1, 16 + ac, env); } } +#endif static inline int32_t mipsdsp_mul_i16_i16(int16_t a, int16_t b, CPUMIPSState *env) @@ -348,10 +350,12 @@ static inline int32_t mipsdsp_mul_u16_u16(int32_t a, int32_t b) return a * b; } +#ifdef TARGET_MIPS64 static inline int32_t mipsdsp_mul_i32_i32(int32_t a, int32_t b) { return a * b; } +#endif static inline int32_t mipsdsp_sat16_mul_i16_i16(int16_t a, int16_t b, CPUMIPSState *env) @@ -408,10 +412,12 @@ static inline int16_t mipsdsp_rashift16(int16_t a, target_ulong mov) return a >> mov; } +#ifdef TARGET_MIPS64 static inline int32_t mipsdsp_rashift32(int32_t a, target_ulong mov) { return a >> mov; } +#endif static inline int16_t mipsdsp_rshift1_add_q16(int16_t a, int16_t b) { @@ -470,6 +476,7 @@ static inline uint8_t mipsdsp_rrshift1_add_u8(uint8_t a, uint8_t b) return (temp >> 1) & 0x00FF; } +#ifdef TARGET_MIPS64 static inline uint8_t mipsdsp_rshift1_sub_u8(uint8_t a, uint8_t b) { uint16_t temp; @@ -487,6 +494,7 @@ static inline uint8_t mipsdsp_rrshift1_sub_u8(uint8_t a, uint8_t b) return (temp >> 1) & 0x00FF; } +#endif /* 128 bits long. p[0] is LO, p[1] is HI. */ static inline void mipsdsp_rndrashift_short_acc(int64_t *p, @@ -502,6 +510,7 @@ static inline void mipsdsp_rndrashift_short_acc(int64_t *p, p[1] = (acc >> 63) & 0x01; } +#ifdef TARGET_MIPS64 /* 128 bits long. p[0] is LO, p[1] is HI */ static inline void mipsdsp_rashift_acc(uint64_t *p, uint32_t ac, @@ -549,6 +558,7 @@ static inline void mipsdsp_rndrashift_acc(uint64_t *p, } } } +#endif static inline int32_t mipsdsp_mul_q15_q15(int32_t ac, uint16_t a, uint16_t b, CPUMIPSState *env) @@ -599,10 +609,12 @@ static inline uint16_t mipsdsp_mul_u8_u16(uint8_t a, uint16_t b, return tempI & 0x0000FFFF; } +#ifdef TARGET_MIPS64 static inline uint64_t mipsdsp_mul_u32_u32(uint32_t a, uint32_t b) { return (uint64_t)a * (uint64_t)b; } +#endif static inline int16_t mipsdsp_rndq15_mul_q15_q15(uint16_t a, uint16_t b, CPUMIPSState *env) @@ -708,7 +720,7 @@ static inline uint16_t mipsdsp_lshift16(uint16_t a, uint8_t s, return a << s; } - +#ifdef TARGET_MIPS64 static inline uint32_t mipsdsp_lshift32(uint32_t a, uint8_t s, CPUMIPSState *env) { @@ -725,6 +737,7 @@ static inline uint32_t mipsdsp_lshift32(uint32_t a, uint8_t s, return a << s; } } +#endif static inline uint16_t mipsdsp_sat16_lshift(uint16_t a, uint8_t s, CPUMIPSState *env) @@ -964,6 +977,7 @@ static inline uint8_t mipsdsp_satu8_sub(uint8_t a, uint8_t b, CPUMIPSState *env) return temp & 0x00FF; } +#ifdef TARGET_MIPS64 static inline uint32_t mipsdsp_sub32(int32_t a, int32_t b, CPUMIPSState *env) { int32_t temp; @@ -988,6 +1002,7 @@ static inline int32_t mipsdsp_add_i32(int32_t a, int32_t b, CPUMIPSState *env) return temp; } +#endif static inline int32_t mipsdsp_cmp_eq(int32_t a, int32_t b) { From 340fff722d8a7cf9c0d4f1e1b4fad03a145a9657 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Sun, 14 Sep 2014 20:45:34 +0100 Subject: [PATCH 28/28] target-mips: Remove unused gen_load_ACX, gen_store_ACX and cpu_ACX Remove the functions gen_load_ACX and gen_store_ACX, which appear to have been unused since they were first introduced many years ago. These functions were the only places using the cpu_ACX[] array of TCG globals, so remove that and its accompanying regnames_ACX[] as well. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Signed-off-by: Leon Alrae --- target-mips/translate.c | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/target-mips/translate.c b/target-mips/translate.c index c23cb94538..446eb8a20f 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -1104,7 +1104,7 @@ enum { /* global register indices */ 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_HI[MIPS_DSP_ACC], cpu_LO[MIPS_DSP_ACC]; static TCGv cpu_dspctrl, btarget, bcond; static TCGv_i32 hflags; static TCGv_i32 fpu_fcr0, fpu_fcr31; @@ -1195,10 +1195,6 @@ static const char * const regnames_LO[] = { "LO0", "LO1", "LO2", "LO3", }; -static const char * const regnames_ACX[] = { - "ACX0", "ACX1", "ACX2", "ACX3", -}; - static const char * const fregnames[] = { "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", @@ -1241,17 +1237,6 @@ static inline void gen_store_gpr (TCGv t, int reg) tcg_gen_mov_tl(cpu_gpr[reg], t); } -/* Moves to/from ACX register. */ -static inline void gen_load_ACX (TCGv t, int reg) -{ - tcg_gen_mov_tl(t, cpu_ACX[reg]); -} - -static inline void gen_store_ACX (TCGv t, int reg) -{ - tcg_gen_mov_tl(cpu_ACX[reg], t); -} - /* Moves to/from shadow registers. */ static inline void gen_load_srsgpr (int from, int to) { @@ -17716,9 +17701,6 @@ void mips_tcg_init(void) cpu_LO[i] = tcg_global_mem_new(TCG_AREG0, offsetof(CPUMIPSState, active_tc.LO[i]), regnames_LO[i]); - cpu_ACX[i] = tcg_global_mem_new(TCG_AREG0, - offsetof(CPUMIPSState, active_tc.ACX[i]), - regnames_ACX[i]); } cpu_dspctrl = tcg_global_mem_new(TCG_AREG0, offsetof(CPUMIPSState, active_tc.DSPControl),