diff options
Diffstat (limited to 'target-mips')
-rw-r--r-- | target-mips/translate.c | 267 |
1 files changed, 161 insertions, 106 deletions
diff --git a/target-mips/translate.c b/target-mips/translate.c index ee3668574a..62fff7ef32 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -57,10 +57,12 @@ enum { OPC_ADDIU = (0x09 << 26), OPC_SLTI = (0x0A << 26), OPC_SLTIU = (0x0B << 26), + /* logic with immediate */ OPC_ANDI = (0x0C << 26), OPC_ORI = (0x0D << 26), OPC_XORI = (0x0E << 26), OPC_LUI = (0x0F << 26), + /* arithmetic with immediate */ OPC_DADDI = (0x18 << 26), OPC_DADDIU = (0x19 << 26), /* Jump and branches */ @@ -1197,140 +1199,184 @@ static void gen_flt_ldst (DisasContext *ctx, uint32_t opc, int ft, static void gen_arith_imm (CPUState *env, DisasContext *ctx, uint32_t opc, int rt, int rs, int16_t imm) { - target_ulong uimm; + target_ulong uimm = (target_long)imm; /* Sign extend to 32/64 bits */ const char *opn = "imm arith"; - TCGv t0 = tcg_temp_local_new(); if (rt == 0 && opc != OPC_ADDI && opc != OPC_DADDI) { /* If no destination, treat it as a NOP. For addi, we must generate the overflow exception when needed. */ MIPS_DEBUG("NOP"); - goto out; - } - uimm = (uint16_t)imm; - switch (opc) { - case OPC_ADDI: - case OPC_ADDIU: -#if defined(TARGET_MIPS64) - case OPC_DADDI: - case OPC_DADDIU: -#endif - case OPC_SLTI: - case OPC_SLTIU: - uimm = (target_long)imm; /* Sign extend to 32/64 bits */ - /* Fall through. */ - case OPC_ANDI: - case OPC_ORI: - case OPC_XORI: - gen_load_gpr(t0, rs); - break; - case OPC_LUI: - tcg_gen_movi_tl(t0, imm << 16); - break; - case OPC_SLL: - case OPC_SRA: - case OPC_SRL: -#if defined(TARGET_MIPS64) - case OPC_DSLL: - case OPC_DSRA: - case OPC_DSRL: - case OPC_DSLL32: - case OPC_DSRA32: - case OPC_DSRL32: -#endif - uimm &= 0x1f; - gen_load_gpr(t0, rs); - break; + return; } switch (opc) { case OPC_ADDI: { - TCGv r_tmp1 = tcg_temp_new(); - TCGv r_tmp2 = tcg_temp_new(); + TCGv t0 = tcg_temp_local_new(); + TCGv t1 = tcg_temp_new(); + TCGv t2 = tcg_temp_new(); int l1 = gen_new_label(); - save_cpu_state(ctx, 1); - tcg_gen_ext32s_tl(r_tmp1, t0); - tcg_gen_addi_tl(t0, r_tmp1, uimm); + gen_load_gpr(t1, rs); + tcg_gen_addi_tl(t0, t1, uimm); + tcg_gen_ext32s_tl(t0, t0); - tcg_gen_xori_tl(r_tmp1, r_tmp1, ~uimm); - tcg_gen_xori_tl(r_tmp2, t0, uimm); - tcg_gen_and_tl(r_tmp1, r_tmp1, r_tmp2); - tcg_temp_free(r_tmp2); - tcg_gen_brcondi_tl(TCG_COND_GE, r_tmp1, 0, l1); + tcg_gen_xori_tl(t1, t1, ~uimm); + tcg_gen_xori_tl(t2, t0, uimm); + tcg_gen_and_tl(t1, t1, t2); + tcg_temp_free(t2); + tcg_gen_brcondi_tl(TCG_COND_GE, t1, 0, l1); + tcg_temp_free(t1); /* operands of same sign, result different sign */ generate_exception(ctx, EXCP_OVERFLOW); gen_set_label(l1); - tcg_temp_free(r_tmp1); - tcg_gen_ext32s_tl(t0, t0); + gen_store_gpr(t0, rt); + tcg_temp_free(t0); } opn = "addi"; break; case OPC_ADDIU: - tcg_gen_addi_tl(t0, t0, uimm); - tcg_gen_ext32s_tl(t0, t0); + if (rs != 0) { + tcg_gen_addi_tl(cpu_gpr[rt], cpu_gpr[rs], uimm); + tcg_gen_ext32s_tl(cpu_gpr[rt], cpu_gpr[rt]); + } else { + tcg_gen_movi_tl(cpu_gpr[rt], uimm); + } opn = "addiu"; break; #if defined(TARGET_MIPS64) case OPC_DADDI: { - TCGv r_tmp1 = tcg_temp_new(); - TCGv r_tmp2 = tcg_temp_new(); + TCGv t0 = tcg_temp_local_new(); + TCGv t1 = tcg_temp_new(); + TCGv t2 = tcg_temp_new(); int l1 = gen_new_label(); - save_cpu_state(ctx, 1); - tcg_gen_mov_tl(r_tmp1, t0); - tcg_gen_addi_tl(t0, t0, uimm); + gen_load_gpr(t1, rs); + tcg_gen_addi_tl(t0, t1, uimm); - tcg_gen_xori_tl(r_tmp1, r_tmp1, ~uimm); - tcg_gen_xori_tl(r_tmp2, t0, uimm); - tcg_gen_and_tl(r_tmp1, r_tmp1, r_tmp2); - tcg_temp_free(r_tmp2); - tcg_gen_brcondi_tl(TCG_COND_GE, r_tmp1, 0, l1); + tcg_gen_xori_tl(t1, t1, ~uimm); + tcg_gen_xori_tl(t2, t0, uimm); + tcg_gen_and_tl(t1, t1, t2); + tcg_temp_free(t2); + tcg_gen_brcondi_tl(TCG_COND_GE, t1, 0, l1); + tcg_temp_free(t1); /* operands of same sign, result different sign */ generate_exception(ctx, EXCP_OVERFLOW); gen_set_label(l1); - tcg_temp_free(r_tmp1); + gen_store_gpr(t0, rt); + tcg_temp_free(t0); } opn = "daddi"; break; case OPC_DADDIU: - tcg_gen_addi_tl(t0, t0, uimm); + if (rs != 0) { + tcg_gen_addi_tl(cpu_gpr[rt], cpu_gpr[rs], uimm); + } else { + tcg_gen_movi_tl(cpu_gpr[rt], uimm); + } opn = "daddiu"; break; #endif - case OPC_SLTI: - gen_op_lti(t0, t0, uimm); - opn = "slti"; - break; - case OPC_SLTIU: - gen_op_ltiu(t0, t0, uimm); - opn = "sltiu"; - break; + } + MIPS_DEBUG("%s %s, %s, " TARGET_FMT_lx, opn, regnames[rt], regnames[rs], uimm); +} + +/* Logic with immediate operand */ +static void gen_logic_imm (CPUState *env, uint32_t opc, int rt, int rs, int16_t imm) +{ + target_ulong uimm; + const char *opn = "imm logic"; + + if (rt == 0) { + /* If no destination, treat it as a NOP. */ + MIPS_DEBUG("NOP"); + return; + } + uimm = (uint16_t)imm; + switch (opc) { case OPC_ANDI: - tcg_gen_andi_tl(t0, t0, uimm); + if (likely(rs != 0)) + tcg_gen_andi_tl(cpu_gpr[rt], cpu_gpr[rs], uimm); + else + tcg_gen_movi_tl(cpu_gpr[rt], 0); opn = "andi"; break; case OPC_ORI: - tcg_gen_ori_tl(t0, t0, uimm); + if (rs != 0) + tcg_gen_ori_tl(cpu_gpr[rt], cpu_gpr[rs], uimm); + else + tcg_gen_movi_tl(cpu_gpr[rt], uimm); opn = "ori"; break; case OPC_XORI: - tcg_gen_xori_tl(t0, t0, uimm); + if (likely(rs != 0)) + tcg_gen_xori_tl(cpu_gpr[rt], cpu_gpr[rs], uimm); + else + tcg_gen_movi_tl(cpu_gpr[rt], uimm); opn = "xori"; break; case OPC_LUI: + tcg_gen_movi_tl(cpu_gpr[rt], imm << 16); opn = "lui"; break; + } + MIPS_DEBUG("%s %s, %s, " TARGET_FMT_lx, opn, regnames[rt], regnames[rs], uimm); +} + +/* Set on less than with immediate operand */ +static void gen_slt_imm (CPUState *env, uint32_t opc, int rt, int rs, int16_t imm) +{ + target_ulong uimm = (target_long)imm; /* Sign extend to 32/64 bits */ + const char *opn = "imm arith"; + TCGv t0; + + if (rt == 0) { + /* If no destination, treat it as a NOP. */ + MIPS_DEBUG("NOP"); + return; + } + t0 = tcg_temp_new(); + gen_load_gpr(t0, rs); + switch (opc) { + case OPC_SLTI: + gen_op_lti(cpu_gpr[rt], t0, uimm); + opn = "slti"; + break; + case OPC_SLTIU: + gen_op_ltiu(cpu_gpr[rt], t0, uimm); + opn = "sltiu"; + break; + } + MIPS_DEBUG("%s %s, %s, " TARGET_FMT_lx, opn, regnames[rt], regnames[rs], uimm); + tcg_temp_free(t0); +} + +/* Shifts with immediate operand */ +static void gen_shift_imm(CPUState *env, DisasContext *ctx, uint32_t opc, + int rt, int rs, int16_t imm) +{ + target_ulong uimm = ((uint16_t)imm) & 0x1f; + const char *opn = "imm shift"; + TCGv t0; + + if (rt == 0) { + /* If no destination, treat it as a NOP. */ + MIPS_DEBUG("NOP"); + return; + } + + t0 = tcg_temp_new(); + gen_load_gpr(t0, rs); + switch (opc) { case OPC_SLL: tcg_gen_shli_tl(t0, t0, uimm); - tcg_gen_ext32s_tl(t0, t0); + tcg_gen_ext32s_tl(cpu_gpr[rt], t0); opn = "sll"; break; case OPC_SRA: tcg_gen_ext32s_tl(t0, t0); - tcg_gen_sari_tl(t0, t0, uimm); + tcg_gen_sari_tl(cpu_gpr[rt], t0, uimm); opn = "sra"; break; case OPC_SRL: @@ -1338,9 +1384,9 @@ static void gen_arith_imm (CPUState *env, DisasContext *ctx, uint32_t opc, case 0: if (uimm != 0) { tcg_gen_ext32u_tl(t0, t0); - tcg_gen_shri_tl(t0, t0, uimm); + tcg_gen_shri_tl(cpu_gpr[rt], t0, uimm); } else { - tcg_gen_ext32s_tl(t0, t0); + tcg_gen_ext32s_tl(cpu_gpr[rt], t0); } opn = "srl"; break; @@ -1352,16 +1398,16 @@ static void gen_arith_imm (CPUState *env, DisasContext *ctx, uint32_t opc, tcg_gen_trunc_tl_i32(r_tmp1, t0); tcg_gen_rotri_i32(r_tmp1, r_tmp1, uimm); - tcg_gen_ext_i32_tl(t0, r_tmp1); + tcg_gen_ext_i32_tl(cpu_gpr[rt], r_tmp1); tcg_temp_free_i32(r_tmp1); } opn = "rotr"; } else { if (uimm != 0) { tcg_gen_ext32u_tl(t0, t0); - tcg_gen_shri_tl(t0, t0, uimm); + tcg_gen_shri_tl(cpu_gpr[rt], t0, uimm); } else { - tcg_gen_ext32s_tl(t0, t0); + tcg_gen_ext32s_tl(cpu_gpr[rt], t0); } opn = "srl"; } @@ -1374,28 +1420,28 @@ static void gen_arith_imm (CPUState *env, DisasContext *ctx, uint32_t opc, break; #if defined(TARGET_MIPS64) case OPC_DSLL: - tcg_gen_shli_tl(t0, t0, uimm); + tcg_gen_shli_tl(cpu_gpr[rt], t0, uimm); opn = "dsll"; break; case OPC_DSRA: - tcg_gen_sari_tl(t0, t0, uimm); + tcg_gen_sari_tl(cpu_gpr[rt], t0, uimm); opn = "dsra"; break; case OPC_DSRL: switch ((ctx->opcode >> 21) & 0x1f) { case 0: - tcg_gen_shri_tl(t0, t0, uimm); + tcg_gen_shri_tl(cpu_gpr[rt], t0, uimm); opn = "dsrl"; break; case 1: /* drotr is decoded as dsrl on non-R2 CPUs */ if (env->insn_flags & ISA_MIPS32R2) { if (uimm != 0) { - tcg_gen_rotri_tl(t0, t0, uimm); + tcg_gen_rotri_tl(cpu_gpr[rt], t0, uimm); } opn = "drotr"; } else { - tcg_gen_shri_tl(t0, t0, uimm); + tcg_gen_shri_tl(cpu_gpr[rt], t0, uimm); opn = "dsrl"; } break; @@ -1406,26 +1452,26 @@ static void gen_arith_imm (CPUState *env, DisasContext *ctx, uint32_t opc, } break; case OPC_DSLL32: - tcg_gen_shli_tl(t0, t0, uimm + 32); + tcg_gen_shli_tl(cpu_gpr[rt], t0, uimm + 32); opn = "dsll32"; break; case OPC_DSRA32: - tcg_gen_sari_tl(t0, t0, uimm + 32); + tcg_gen_sari_tl(cpu_gpr[rt], t0, uimm + 32); opn = "dsra32"; break; case OPC_DSRL32: switch ((ctx->opcode >> 21) & 0x1f) { case 0: - tcg_gen_shri_tl(t0, t0, uimm + 32); + tcg_gen_shri_tl(cpu_gpr[rt], t0, uimm + 32); opn = "dsrl32"; break; case 1: /* drotr32 is decoded as dsrl32 on non-R2 CPUs */ if (env->insn_flags & ISA_MIPS32R2) { - tcg_gen_rotri_tl(t0, t0, uimm + 32); + tcg_gen_rotri_tl(cpu_gpr[rt], t0, uimm + 32); opn = "drotr32"; } else { - tcg_gen_shri_tl(t0, t0, uimm + 32); + tcg_gen_shri_tl(cpu_gpr[rt], t0, uimm + 32); opn = "dsrl32"; } break; @@ -1436,14 +1482,8 @@ static void gen_arith_imm (CPUState *env, DisasContext *ctx, uint32_t opc, } break; #endif - default: - MIPS_INVAL(opn); - generate_exception(ctx, EXCP_RI); - goto out; } - gen_store_gpr(t0, rt); MIPS_DEBUG("%s %s, %s, " TARGET_FMT_lx, opn, regnames[rt], regnames[rs], uimm); - out: tcg_temp_free(t0); } @@ -7556,9 +7596,10 @@ static void decode_opc (CPUState *env, DisasContext *ctx) case OPC_SPECIAL: op1 = MASK_SPECIAL(ctx->opcode); switch (op1) { - case OPC_SLL: /* Arithmetic with immediate */ - case OPC_SRL ... OPC_SRA: - gen_arith_imm(env, ctx, op1, rd, rt, sa); + case OPC_SLL: /* Shift with immediate */ + case OPC_SRA: + case OPC_SRL: + gen_shift_imm(env, ctx, op1, rd, rt, sa); break; case OPC_MOVN: /* Conditional move */ case OPC_MOVZ: @@ -7648,12 +7689,14 @@ static void decode_opc (CPUState *env, DisasContext *ctx) #if defined(TARGET_MIPS64) /* MIPS64 specific opcodes */ case OPC_DSLL: - case OPC_DSRL ... OPC_DSRA: + case OPC_DSRA: + case OPC_DSRL: case OPC_DSLL32: - case OPC_DSRL32 ... OPC_DSRA32: + case OPC_DSRA32: + case OPC_DSRL32: check_insn(env, ctx, ISA_MIPS3); check_mips_64(ctx); - gen_arith_imm(env, ctx, op1, rd, rt, sa); + gen_shift_imm(env, ctx, op1, rd, rt, sa); break; case OPC_DADD ... OPC_DSUBU: check_insn(env, ctx, ISA_MIPS3); @@ -7928,9 +7971,20 @@ static void decode_opc (CPUState *env, DisasContext *ctx) break; } break; - case OPC_ADDI ... OPC_LUI: /* Arithmetic with immediate opcode */ + case OPC_ADDI: /* Arithmetic with immediate opcode */ + case OPC_ADDIU: gen_arith_imm(env, ctx, op, rt, rs, imm); break; + case OPC_SLTI: /* Set on less than with immediate opcode */ + case OPC_SLTIU: + gen_slt_imm(env, op, rt, rs, imm); + break; + case OPC_ANDI: /* Arithmetic with immediate opcode */ + case OPC_LUI: + case OPC_ORI: + case OPC_XORI: + gen_logic_imm(env, op, rt, rs, imm); + break; case OPC_J ... OPC_JAL: /* Jump */ offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 2; gen_compute_branch(ctx, op, rs, rt, offset); @@ -8080,7 +8134,8 @@ static void decode_opc (CPUState *env, DisasContext *ctx) check_mips_64(ctx); gen_ldst(ctx, op, rt, rs, imm); break; - case OPC_DADDI ... OPC_DADDIU: + case OPC_DADDI: + case OPC_DADDIU: check_insn(env, ctx, ISA_MIPS3); check_mips_64(ctx); gen_arith_imm(env, ctx, op, rt, rs, imm); |