target-mips: move ROTR and ROTRV inside gen_shift_{imm, }

It's easier to implement mips16 shift instructions if we're not
examining the opcode inside gen_shift_{imm,}.  So move ROTR and ROTRV
and do the special-case handling of SRL and SRLV inside decode_opc.
Likewise for their 64-bit counterparts.

Signed-off-by: Nathan Froyd <froydnj@codesourcery.com>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
This commit is contained in:
Nathan Froyd 2009-12-08 08:06:24 -08:00 committed by Aurelien Jarno
parent 32188a03da
commit ea63e2c358
1 changed files with 147 additions and 138 deletions

View File

@ -128,18 +128,23 @@ enum {
/* SSNOP is SLL r0, r0, 1 */
/* EHB is SLL r0, r0, 3 */
OPC_SRL = 0x02 | OPC_SPECIAL, /* also ROTR */
OPC_ROTR = OPC_SRL | (1 << 21),
OPC_SRA = 0x03 | OPC_SPECIAL,
OPC_SLLV = 0x04 | OPC_SPECIAL,
OPC_SRLV = 0x06 | OPC_SPECIAL, /* also ROTRV */
OPC_ROTRV = OPC_SRLV | (1 << 6),
OPC_SRAV = 0x07 | OPC_SPECIAL,
OPC_DSLLV = 0x14 | OPC_SPECIAL,
OPC_DSRLV = 0x16 | OPC_SPECIAL, /* also DROTRV */
OPC_DROTRV = OPC_DSRLV | (1 << 6),
OPC_DSRAV = 0x17 | OPC_SPECIAL,
OPC_DSLL = 0x38 | OPC_SPECIAL,
OPC_DSRL = 0x3A | OPC_SPECIAL, /* also DROTR */
OPC_DROTR = OPC_DSRL | (1 << 21),
OPC_DSRA = 0x3B | OPC_SPECIAL,
OPC_DSLL32 = 0x3C | OPC_SPECIAL,
OPC_DSRL32 = 0x3E | OPC_SPECIAL, /* also DROTR32 */
OPC_DROTR32 = OPC_DSRL32 | (1 << 21),
OPC_DSRA32 = 0x3F | OPC_SPECIAL,
/* Multiplication / division */
OPC_MULT = 0x18 | OPC_SPECIAL,
@ -1431,43 +1436,24 @@ static void gen_shift_imm(CPUState *env, DisasContext *ctx, uint32_t opc,
opn = "sra";
break;
case OPC_SRL:
switch ((ctx->opcode >> 21) & 0x1f) {
case 0:
if (uimm != 0) {
tcg_gen_ext32u_tl(t0, t0);
tcg_gen_shri_tl(cpu_gpr[rt], t0, uimm);
} else {
tcg_gen_ext32s_tl(cpu_gpr[rt], t0);
}
opn = "srl";
break;
case 1:
/* rotr is decoded as srl on non-R2 CPUs */
if (env->insn_flags & ISA_MIPS32R2) {
if (uimm != 0) {
TCGv_i32 t1 = tcg_temp_new_i32();
tcg_gen_trunc_tl_i32(t1, t0);
tcg_gen_rotri_i32(t1, t1, uimm);
tcg_gen_ext_i32_tl(cpu_gpr[rt], t1);
tcg_temp_free_i32(t1);
}
opn = "rotr";
} else {
if (uimm != 0) {
tcg_gen_ext32u_tl(t0, t0);
tcg_gen_shri_tl(cpu_gpr[rt], t0, uimm);
} else {
tcg_gen_ext32s_tl(cpu_gpr[rt], t0);
}
opn = "srl";
}
break;
default:
MIPS_INVAL("invalid srl flag");
generate_exception(ctx, EXCP_RI);
break;
if (uimm != 0) {
tcg_gen_ext32u_tl(t0, t0);
tcg_gen_shri_tl(cpu_gpr[rt], t0, uimm);
} else {
tcg_gen_ext32s_tl(cpu_gpr[rt], t0);
}
opn = "srl";
break;
case OPC_ROTR:
if (uimm != 0) {
TCGv_i32 t1 = tcg_temp_new_i32();
tcg_gen_trunc_tl_i32(t1, t0);
tcg_gen_rotri_i32(t1, t1, uimm);
tcg_gen_ext_i32_tl(cpu_gpr[rt], t1);
tcg_temp_free_i32(t1);
}
opn = "rotr";
break;
#if defined(TARGET_MIPS64)
case OPC_DSLL:
@ -1479,28 +1465,14 @@ static void gen_shift_imm(CPUState *env, DisasContext *ctx, uint32_t opc,
opn = "dsra";
break;
case OPC_DSRL:
switch ((ctx->opcode >> 21) & 0x1f) {
case 0:
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(cpu_gpr[rt], t0, uimm);
}
opn = "drotr";
} else {
tcg_gen_shri_tl(cpu_gpr[rt], t0, uimm);
opn = "dsrl";
}
break;
default:
MIPS_INVAL("invalid dsrl flag");
generate_exception(ctx, EXCP_RI);
break;
tcg_gen_shri_tl(cpu_gpr[rt], t0, uimm);
opn = "dsrl";
break;
case OPC_DROTR:
if (uimm != 0) {
tcg_gen_rotri_tl(cpu_gpr[rt], t0, uimm);
}
opn = "drotr";
break;
case OPC_DSLL32:
tcg_gen_shli_tl(cpu_gpr[rt], t0, uimm + 32);
@ -1511,26 +1483,12 @@ static void gen_shift_imm(CPUState *env, DisasContext *ctx, uint32_t opc,
opn = "dsra32";
break;
case OPC_DSRL32:
switch ((ctx->opcode >> 21) & 0x1f) {
case 0:
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(cpu_gpr[rt], t0, uimm + 32);
opn = "drotr32";
} else {
tcg_gen_shri_tl(cpu_gpr[rt], t0, uimm + 32);
opn = "dsrl32";
}
break;
default:
MIPS_INVAL("invalid dsrl32 flag");
generate_exception(ctx, EXCP_RI);
break;
}
tcg_gen_shri_tl(cpu_gpr[rt], t0, uimm + 32);
opn = "dsrl32";
break;
case OPC_DROTR32:
tcg_gen_rotri_tl(cpu_gpr[rt], t0, uimm + 32);
opn = "drotr32";
break;
#endif
}
@ -1879,40 +1837,25 @@ static void gen_shift (CPUState *env, DisasContext *ctx, uint32_t opc,
opn = "srav";
break;
case OPC_SRLV:
switch ((ctx->opcode >> 6) & 0x1f) {
case 0:
tcg_gen_ext32u_tl(t1, t1);
tcg_gen_andi_tl(t0, t0, 0x1f);
tcg_gen_shr_tl(t0, t1, t0);
tcg_gen_ext32s_tl(cpu_gpr[rd], t0);
opn = "srlv";
break;
case 1:
/* rotrv is decoded as srlv on non-R2 CPUs */
if (env->insn_flags & ISA_MIPS32R2) {
TCGv_i32 t2 = tcg_temp_new_i32();
TCGv_i32 t3 = tcg_temp_new_i32();
tcg_gen_ext32u_tl(t1, t1);
tcg_gen_andi_tl(t0, t0, 0x1f);
tcg_gen_shr_tl(t0, t1, t0);
tcg_gen_ext32s_tl(cpu_gpr[rd], t0);
opn = "srlv";
break;
case OPC_ROTRV:
{
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_andi_i32(t2, t2, 0x1f);
tcg_gen_rotr_i32(t2, t3, t2);
tcg_gen_ext_i32_tl(cpu_gpr[rd], t2);
tcg_temp_free_i32(t2);
tcg_temp_free_i32(t3);
opn = "rotrv";
} else {
tcg_gen_ext32u_tl(t1, t1);
tcg_gen_andi_tl(t0, t0, 0x1f);
tcg_gen_shr_tl(t0, t1, t0);
tcg_gen_ext32s_tl(cpu_gpr[rd], t0);
opn = "srlv";
}
break;
default:
MIPS_INVAL("invalid srlv flag");
generate_exception(ctx, EXCP_RI);
break;
tcg_gen_trunc_tl_i32(t2, t0);
tcg_gen_trunc_tl_i32(t3, t1);
tcg_gen_andi_i32(t2, t2, 0x1f);
tcg_gen_rotr_i32(t2, t3, t2);
tcg_gen_ext_i32_tl(cpu_gpr[rd], t2);
tcg_temp_free_i32(t2);
tcg_temp_free_i32(t3);
opn = "rotrv";
}
break;
#if defined(TARGET_MIPS64)
@ -1927,29 +1870,14 @@ static void gen_shift (CPUState *env, DisasContext *ctx, uint32_t opc,
opn = "dsrav";
break;
case OPC_DSRLV:
switch ((ctx->opcode >> 6) & 0x1f) {
case 0:
tcg_gen_andi_tl(t0, t0, 0x3f);
tcg_gen_shr_tl(cpu_gpr[rd], t1, t0);
opn = "dsrlv";
break;
case 1:
/* drotrv is decoded as dsrlv on non-R2 CPUs */
if (env->insn_flags & ISA_MIPS32R2) {
tcg_gen_andi_tl(t0, t0, 0x3f);
tcg_gen_rotr_tl(cpu_gpr[rd], t1, t0);
opn = "drotrv";
} else {
tcg_gen_andi_tl(t0, t0, 0x3f);
tcg_gen_shr_tl(t0, t1, t0);
opn = "dsrlv";
}
break;
default:
MIPS_INVAL("invalid dsrlv flag");
generate_exception(ctx, EXCP_RI);
break;
}
tcg_gen_andi_tl(t0, t0, 0x3f);
tcg_gen_shr_tl(cpu_gpr[rd], t1, t0);
opn = "dsrlv";
break;
case OPC_DROTRV:
tcg_gen_andi_tl(t0, t0, 0x3f);
tcg_gen_rotr_tl(cpu_gpr[rd], t1, t0);
opn = "drotrv";
break;
#endif
}
@ -7661,9 +7589,24 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
switch (op1) {
case OPC_SLL: /* Shift with immediate */
case OPC_SRA:
case OPC_SRL:
gen_shift_imm(env, 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 (env->insn_flags & ISA_MIPS32R2) {
op1 = OPC_ROTR;
}
/* Fallthrough */
case 0:
gen_shift_imm(env, ctx, op1, rd, rt, sa);
break;
default:
generate_exception(ctx, EXCP_RI);
break;
}
break;
case OPC_MOVN: /* Conditional move */
case OPC_MOVZ:
check_insn(env, ctx, ISA_MIPS4 | ISA_MIPS32);
@ -7673,10 +7616,25 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
gen_arith(env, ctx, op1, rd, rs, rt);
break;
case OPC_SLLV: /* Shifts */
case OPC_SRLV:
case OPC_SRAV:
gen_shift(env, 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 (env->insn_flags & ISA_MIPS32R2) {
op1 = OPC_ROTRV;
}
/* Fallthrough */
case 0:
gen_shift(env, 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(env, op1, rd, rs, rt);
@ -7754,14 +7712,48 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
/* MIPS64 specific opcodes */
case OPC_DSLL:
case OPC_DSRA:
case OPC_DSRL:
case OPC_DSLL32:
case OPC_DSRA32:
case OPC_DSRL32:
check_insn(env, ctx, ISA_MIPS3);
check_mips_64(ctx);
gen_shift_imm(env, 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 (env->insn_flags & ISA_MIPS32R2) {
op1 = OPC_DROTR;
}
/* Fallthrough */
case 0:
check_insn(env, ctx, ISA_MIPS3);
check_mips_64(ctx);
gen_shift_imm(env, 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 (env->insn_flags & ISA_MIPS32R2) {
op1 = OPC_DROTR32;
}
/* Fallthrough */
case 0:
check_insn(env, ctx, ISA_MIPS3);
check_mips_64(ctx);
gen_shift_imm(env, ctx, op1, rd, rt, sa);
break;
default:
generate_exception(ctx, EXCP_RI);
break;
}
break;
case OPC_DADD ... OPC_DSUBU:
check_insn(env, ctx, ISA_MIPS3);
check_mips_64(ctx);
@ -7769,11 +7761,28 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
break;
case OPC_DSLLV:
case OPC_DSRAV:
case OPC_DSRLV:
check_insn(env, ctx, ISA_MIPS3);
check_mips_64(ctx);
gen_shift(env, 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 (env->insn_flags & ISA_MIPS32R2) {
op1 = OPC_DROTRV;
}
/* Fallthrough */
case 0:
check_insn(env, ctx, ISA_MIPS3);
check_mips_64(ctx);
gen_shift(env, ctx, op1, rd, rs, rt);
break;
default:
generate_exception(ctx, EXCP_RI);
break;
}
break;
case OPC_DMULT ... OPC_DDIVU:
check_insn(env, ctx, ISA_MIPS3);
check_mips_64(ctx);