mirror of
https://git.proxmox.com/git/qemu
synced 2025-07-09 08:42:32 +00:00
target-mips: optimize gen_arith()
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@7043 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
parent
35fbce2c41
commit
460f00c4e1
@ -1452,200 +1452,338 @@ static void gen_arith (CPUState *env, DisasContext *ctx, uint32_t opc,
|
|||||||
int rd, int rs, int rt)
|
int rd, int rs, int rt)
|
||||||
{
|
{
|
||||||
const char *opn = "arith";
|
const char *opn = "arith";
|
||||||
TCGv t0 = tcg_temp_local_new();
|
|
||||||
TCGv t1 = tcg_temp_local_new();
|
|
||||||
|
|
||||||
if (rd == 0 && opc != OPC_ADD && opc != OPC_SUB
|
if (rd == 0 && opc != OPC_ADD && opc != OPC_SUB
|
||||||
&& opc != OPC_DADD && opc != OPC_DSUB) {
|
&& opc != OPC_DADD && opc != OPC_DSUB) {
|
||||||
/* If no destination, treat it as a NOP.
|
/* If no destination, treat it as a NOP.
|
||||||
For add & sub, we must generate the overflow exception when needed. */
|
For add & sub, we must generate the overflow exception when needed. */
|
||||||
MIPS_DEBUG("NOP");
|
MIPS_DEBUG("NOP");
|
||||||
goto out;
|
return;
|
||||||
}
|
}
|
||||||
gen_load_gpr(t0, rs);
|
|
||||||
/* Specialcase the conventional move operation. */
|
|
||||||
if (rt == 0 && (opc == OPC_ADDU || opc == OPC_DADDU
|
|
||||||
|| opc == OPC_SUBU || opc == OPC_DSUBU)) {
|
|
||||||
gen_store_gpr(t0, rd);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
gen_load_gpr(t1, rt);
|
|
||||||
switch (opc) {
|
switch (opc) {
|
||||||
case OPC_ADD:
|
case OPC_ADD:
|
||||||
{
|
{
|
||||||
TCGv r_tmp1 = tcg_temp_new();
|
TCGv t0 = tcg_temp_local_new();
|
||||||
TCGv r_tmp2 = tcg_temp_new();
|
TCGv t1 = tcg_temp_new();
|
||||||
|
TCGv t2 = tcg_temp_new();
|
||||||
int l1 = gen_new_label();
|
int l1 = gen_new_label();
|
||||||
|
|
||||||
save_cpu_state(ctx, 1);
|
gen_load_gpr(t1, rs);
|
||||||
tcg_gen_ext32s_tl(r_tmp1, t0);
|
gen_load_gpr(t2, rt);
|
||||||
tcg_gen_ext32s_tl(r_tmp2, t1);
|
tcg_gen_add_tl(t0, t1, t2);
|
||||||
tcg_gen_add_tl(t0, r_tmp1, r_tmp2);
|
tcg_gen_ext32s_tl(t0, t0);
|
||||||
|
tcg_gen_xor_tl(t1, t1, t2);
|
||||||
tcg_gen_xor_tl(r_tmp1, r_tmp1, t1);
|
tcg_gen_not_tl(t1, t1);
|
||||||
tcg_gen_xori_tl(r_tmp1, r_tmp1, -1);
|
tcg_gen_xor_tl(t2, t0, t2);
|
||||||
tcg_gen_xor_tl(r_tmp2, t0, t1);
|
tcg_gen_and_tl(t1, t1, t2);
|
||||||
tcg_gen_and_tl(r_tmp1, r_tmp1, r_tmp2);
|
tcg_temp_free(t2);
|
||||||
tcg_temp_free(r_tmp2);
|
tcg_gen_brcondi_tl(TCG_COND_GE, t1, 0, l1);
|
||||||
tcg_gen_brcondi_tl(TCG_COND_GE, r_tmp1, 0, l1);
|
tcg_temp_free(t1);
|
||||||
/* operands of same sign, result different sign */
|
/* operands of same sign, result different sign */
|
||||||
generate_exception(ctx, EXCP_OVERFLOW);
|
generate_exception(ctx, EXCP_OVERFLOW);
|
||||||
gen_set_label(l1);
|
gen_set_label(l1);
|
||||||
tcg_temp_free(r_tmp1);
|
gen_store_gpr(t0, rd);
|
||||||
|
tcg_temp_free(t0);
|
||||||
tcg_gen_ext32s_tl(t0, t0);
|
|
||||||
}
|
}
|
||||||
opn = "add";
|
opn = "add";
|
||||||
break;
|
break;
|
||||||
case OPC_ADDU:
|
case OPC_ADDU:
|
||||||
tcg_gen_add_tl(t0, t0, t1);
|
if (rs != 0 && rt != 0) {
|
||||||
tcg_gen_ext32s_tl(t0, t0);
|
tcg_gen_add_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]);
|
||||||
|
tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]);
|
||||||
|
} else if (rs == 0 && rt != 0) {
|
||||||
|
tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rt]);
|
||||||
|
} else if (rs != 0 && rt == 0) {
|
||||||
|
tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rs]);
|
||||||
|
} else {
|
||||||
|
tcg_gen_movi_tl(cpu_gpr[rd], 0);
|
||||||
|
}
|
||||||
opn = "addu";
|
opn = "addu";
|
||||||
break;
|
break;
|
||||||
case OPC_SUB:
|
case OPC_SUB:
|
||||||
{
|
{
|
||||||
TCGv r_tmp1 = tcg_temp_new();
|
TCGv t0 = tcg_temp_local_new();
|
||||||
TCGv r_tmp2 = tcg_temp_new();
|
TCGv t1 = tcg_temp_new();
|
||||||
|
TCGv t2 = tcg_temp_new();
|
||||||
int l1 = gen_new_label();
|
int l1 = gen_new_label();
|
||||||
|
|
||||||
save_cpu_state(ctx, 1);
|
gen_load_gpr(t1, rs);
|
||||||
tcg_gen_ext32s_tl(r_tmp1, t0);
|
gen_load_gpr(t2, rt);
|
||||||
tcg_gen_ext32s_tl(r_tmp2, t1);
|
tcg_gen_sub_tl(t0, t1, t2);
|
||||||
tcg_gen_sub_tl(t0, r_tmp1, r_tmp2);
|
tcg_gen_ext32s_tl(t0, t0);
|
||||||
|
tcg_gen_xor_tl(t2, t1, t2);
|
||||||
tcg_gen_xor_tl(r_tmp2, r_tmp1, t1);
|
tcg_gen_xor_tl(t1, t0, t1);
|
||||||
tcg_gen_xor_tl(r_tmp1, r_tmp1, t0);
|
tcg_gen_and_tl(t1, t1, t2);
|
||||||
tcg_gen_and_tl(r_tmp1, r_tmp1, r_tmp2);
|
tcg_temp_free(t2);
|
||||||
tcg_temp_free(r_tmp2);
|
tcg_gen_brcondi_tl(TCG_COND_GE, t1, 0, l1);
|
||||||
tcg_gen_brcondi_tl(TCG_COND_GE, r_tmp1, 0, l1);
|
tcg_temp_free(t1);
|
||||||
/* operands of different sign, first operand and result different sign */
|
/* operands of same sign, result different sign */
|
||||||
generate_exception(ctx, EXCP_OVERFLOW);
|
generate_exception(ctx, EXCP_OVERFLOW);
|
||||||
gen_set_label(l1);
|
gen_set_label(l1);
|
||||||
tcg_temp_free(r_tmp1);
|
gen_store_gpr(t0, rd);
|
||||||
|
tcg_temp_free(t0);
|
||||||
tcg_gen_ext32s_tl(t0, t0);
|
|
||||||
}
|
}
|
||||||
opn = "sub";
|
opn = "sub";
|
||||||
break;
|
break;
|
||||||
case OPC_SUBU:
|
case OPC_SUBU:
|
||||||
tcg_gen_sub_tl(t0, t0, t1);
|
if (rs != 0 && rt != 0) {
|
||||||
tcg_gen_ext32s_tl(t0, t0);
|
tcg_gen_sub_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]);
|
||||||
|
tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]);
|
||||||
|
} else if (rs == 0 && rt != 0) {
|
||||||
|
tcg_gen_neg_tl(cpu_gpr[rd], cpu_gpr[rt]);
|
||||||
|
} else if (rs != 0 && rt == 0) {
|
||||||
|
tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rs]);
|
||||||
|
} else {
|
||||||
|
tcg_gen_movi_tl(cpu_gpr[rd], 0);
|
||||||
|
}
|
||||||
opn = "subu";
|
opn = "subu";
|
||||||
break;
|
break;
|
||||||
#if defined(TARGET_MIPS64)
|
#if defined(TARGET_MIPS64)
|
||||||
case OPC_DADD:
|
case OPC_DADD:
|
||||||
{
|
{
|
||||||
TCGv r_tmp1 = tcg_temp_new();
|
TCGv t0 = tcg_temp_local_new();
|
||||||
TCGv r_tmp2 = tcg_temp_new();
|
TCGv t1 = tcg_temp_new();
|
||||||
|
TCGv t2 = tcg_temp_new();
|
||||||
int l1 = gen_new_label();
|
int l1 = gen_new_label();
|
||||||
|
|
||||||
save_cpu_state(ctx, 1);
|
gen_load_gpr(t1, rs);
|
||||||
tcg_gen_mov_tl(r_tmp1, t0);
|
gen_load_gpr(t2, rt);
|
||||||
tcg_gen_add_tl(t0, t0, t1);
|
tcg_gen_add_tl(t0, t1, t2);
|
||||||
|
tcg_gen_xor_tl(t1, t1, t2);
|
||||||
tcg_gen_xor_tl(r_tmp1, r_tmp1, t1);
|
tcg_gen_not_tl(t1, t1);
|
||||||
tcg_gen_xori_tl(r_tmp1, r_tmp1, -1);
|
tcg_gen_xor_tl(t2, t0, t2);
|
||||||
tcg_gen_xor_tl(r_tmp2, t0, t1);
|
tcg_gen_and_tl(t1, t1, t2);
|
||||||
tcg_gen_and_tl(r_tmp1, r_tmp1, r_tmp2);
|
tcg_temp_free(t2);
|
||||||
tcg_temp_free(r_tmp2);
|
tcg_gen_brcondi_tl(TCG_COND_GE, t1, 0, l1);
|
||||||
tcg_gen_brcondi_tl(TCG_COND_GE, r_tmp1, 0, l1);
|
tcg_temp_free(t1);
|
||||||
/* operands of same sign, result different sign */
|
/* operands of same sign, result different sign */
|
||||||
generate_exception(ctx, EXCP_OVERFLOW);
|
generate_exception(ctx, EXCP_OVERFLOW);
|
||||||
gen_set_label(l1);
|
gen_set_label(l1);
|
||||||
tcg_temp_free(r_tmp1);
|
gen_store_gpr(t0, rd);
|
||||||
|
tcg_temp_free(t0);
|
||||||
}
|
}
|
||||||
opn = "dadd";
|
opn = "dadd";
|
||||||
break;
|
break;
|
||||||
case OPC_DADDU:
|
case OPC_DADDU:
|
||||||
tcg_gen_add_tl(t0, t0, t1);
|
if (rs != 0 && rt != 0) {
|
||||||
|
tcg_gen_add_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]);
|
||||||
|
} else if (rs == 0 && rt != 0) {
|
||||||
|
tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rt]);
|
||||||
|
} else if (rs != 0 && rt == 0) {
|
||||||
|
tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rs]);
|
||||||
|
} else {
|
||||||
|
tcg_gen_movi_tl(cpu_gpr[rd], 0);
|
||||||
|
}
|
||||||
opn = "daddu";
|
opn = "daddu";
|
||||||
break;
|
break;
|
||||||
case OPC_DSUB:
|
case OPC_DSUB:
|
||||||
{
|
{
|
||||||
TCGv r_tmp1 = tcg_temp_new();
|
TCGv t0 = tcg_temp_local_new();
|
||||||
TCGv r_tmp2 = tcg_temp_new();
|
TCGv t1 = tcg_temp_new();
|
||||||
|
TCGv t2 = tcg_temp_new();
|
||||||
int l1 = gen_new_label();
|
int l1 = gen_new_label();
|
||||||
|
|
||||||
save_cpu_state(ctx, 1);
|
gen_load_gpr(t1, rs);
|
||||||
tcg_gen_mov_tl(r_tmp1, t0);
|
gen_load_gpr(t2, rt);
|
||||||
tcg_gen_sub_tl(t0, t0, t1);
|
tcg_gen_sub_tl(t0, t1, t2);
|
||||||
|
tcg_gen_xor_tl(t2, t1, t2);
|
||||||
tcg_gen_xor_tl(r_tmp2, r_tmp1, t1);
|
tcg_gen_xor_tl(t1, t0, t1);
|
||||||
tcg_gen_xor_tl(r_tmp1, r_tmp1, t0);
|
tcg_gen_and_tl(t1, t1, t2);
|
||||||
tcg_gen_and_tl(r_tmp1, r_tmp1, r_tmp2);
|
tcg_temp_free(t2);
|
||||||
tcg_temp_free(r_tmp2);
|
tcg_gen_brcondi_tl(TCG_COND_GE, t1, 0, l1);
|
||||||
tcg_gen_brcondi_tl(TCG_COND_GE, r_tmp1, 0, l1);
|
tcg_temp_free(t1);
|
||||||
/* operands of different sign, first operand and result different sign */
|
/* operands of same sign, result different sign */
|
||||||
generate_exception(ctx, EXCP_OVERFLOW);
|
generate_exception(ctx, EXCP_OVERFLOW);
|
||||||
gen_set_label(l1);
|
gen_set_label(l1);
|
||||||
tcg_temp_free(r_tmp1);
|
gen_store_gpr(t0, rd);
|
||||||
|
tcg_temp_free(t0);
|
||||||
}
|
}
|
||||||
opn = "dsub";
|
opn = "dsub";
|
||||||
break;
|
break;
|
||||||
case OPC_DSUBU:
|
case OPC_DSUBU:
|
||||||
tcg_gen_sub_tl(t0, t0, t1);
|
if (rs != 0 && rt != 0) {
|
||||||
|
tcg_gen_sub_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]);
|
||||||
|
} else if (rs == 0 && rt != 0) {
|
||||||
|
tcg_gen_neg_tl(cpu_gpr[rd], cpu_gpr[rt]);
|
||||||
|
} else if (rs != 0 && rt == 0) {
|
||||||
|
tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rs]);
|
||||||
|
} else {
|
||||||
|
tcg_gen_movi_tl(cpu_gpr[rd], 0);
|
||||||
|
}
|
||||||
opn = "dsubu";
|
opn = "dsubu";
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
case OPC_SLT:
|
case OPC_MUL:
|
||||||
gen_op_lt(t0, t0, t1);
|
if (likely(rs != 0 && rt != 0)) {
|
||||||
opn = "slt";
|
tcg_gen_mul_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]);
|
||||||
|
tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]);
|
||||||
|
} else {
|
||||||
|
tcg_gen_movi_tl(cpu_gpr[rd], 0);
|
||||||
|
}
|
||||||
|
opn = "mul";
|
||||||
break;
|
break;
|
||||||
case OPC_SLTU:
|
}
|
||||||
gen_op_ltu(t0, t0, t1);
|
MIPS_DEBUG("%s %s, %s, %s", opn, regnames[rd], regnames[rs], regnames[rt]);
|
||||||
opn = "sltu";
|
}
|
||||||
|
|
||||||
|
/* Conditional move */
|
||||||
|
static void gen_cond_move (CPUState *env, uint32_t opc, int rd, int rs, int rt)
|
||||||
|
{
|
||||||
|
const char *opn = "cond move";
|
||||||
|
int l1;
|
||||||
|
|
||||||
|
if (rd == 0) {
|
||||||
|
/* If no destination, treat it as a NOP.
|
||||||
|
For add & sub, we must generate the overflow exception when needed. */
|
||||||
|
MIPS_DEBUG("NOP");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
l1 = gen_new_label();
|
||||||
|
switch (opc) {
|
||||||
|
case OPC_MOVN:
|
||||||
|
if (likely(rt != 0))
|
||||||
|
tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_gpr[rt], 0, l1);
|
||||||
|
else
|
||||||
|
tcg_gen_br(l1);
|
||||||
|
opn = "movn";
|
||||||
break;
|
break;
|
||||||
|
case OPC_MOVZ:
|
||||||
|
if (likely(rt != 0))
|
||||||
|
tcg_gen_brcondi_tl(TCG_COND_NE, cpu_gpr[rt], 0, l1);
|
||||||
|
opn = "movz";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (rs != 0)
|
||||||
|
tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rs]);
|
||||||
|
else
|
||||||
|
tcg_gen_movi_tl(cpu_gpr[rd], 0);
|
||||||
|
gen_set_label(l1);
|
||||||
|
|
||||||
|
MIPS_DEBUG("%s %s, %s, %s", opn, regnames[rd], regnames[rs], regnames[rt]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Logic */
|
||||||
|
static void gen_logic (CPUState *env, uint32_t opc, int rd, int rs, int rt)
|
||||||
|
{
|
||||||
|
const char *opn = "logic";
|
||||||
|
|
||||||
|
if (rd == 0) {
|
||||||
|
/* If no destination, treat it as a NOP. */
|
||||||
|
MIPS_DEBUG("NOP");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (opc) {
|
||||||
case OPC_AND:
|
case OPC_AND:
|
||||||
tcg_gen_and_tl(t0, t0, t1);
|
if (likely(rs != 0 && rt != 0)) {
|
||||||
|
tcg_gen_and_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]);
|
||||||
|
} else {
|
||||||
|
tcg_gen_movi_tl(cpu_gpr[rd], 0);
|
||||||
|
}
|
||||||
opn = "and";
|
opn = "and";
|
||||||
break;
|
break;
|
||||||
case OPC_NOR:
|
case OPC_NOR:
|
||||||
tcg_gen_nor_tl(t0, t0, t1);
|
if (rs != 0 && rt != 0) {
|
||||||
|
tcg_gen_nor_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]);
|
||||||
|
} else if (rs == 0 && rt != 0) {
|
||||||
|
tcg_gen_not_tl(cpu_gpr[rd], cpu_gpr[rt]);
|
||||||
|
} else if (rs != 0 && rt == 0) {
|
||||||
|
tcg_gen_not_tl(cpu_gpr[rd], cpu_gpr[rs]);
|
||||||
|
} else {
|
||||||
|
tcg_gen_movi_tl(cpu_gpr[rd], ~((target_ulong)0));
|
||||||
|
}
|
||||||
opn = "nor";
|
opn = "nor";
|
||||||
break;
|
break;
|
||||||
case OPC_OR:
|
case OPC_OR:
|
||||||
tcg_gen_or_tl(t0, t0, t1);
|
if (likely(rs != 0 && rt != 0)) {
|
||||||
|
tcg_gen_or_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]);
|
||||||
|
} else if (rs == 0 && rt != 0) {
|
||||||
|
tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rt]);
|
||||||
|
} else if (rs != 0 && rt == 0) {
|
||||||
|
tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rs]);
|
||||||
|
} else {
|
||||||
|
tcg_gen_movi_tl(cpu_gpr[rd], 0);
|
||||||
|
}
|
||||||
opn = "or";
|
opn = "or";
|
||||||
break;
|
break;
|
||||||
case OPC_XOR:
|
case OPC_XOR:
|
||||||
tcg_gen_xor_tl(t0, t0, t1);
|
if (likely(rs != 0 && rt != 0)) {
|
||||||
|
tcg_gen_xor_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]);
|
||||||
|
} else if (rs == 0 && rt != 0) {
|
||||||
|
tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rt]);
|
||||||
|
} else if (rs != 0 && rt == 0) {
|
||||||
|
tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rs]);
|
||||||
|
} else {
|
||||||
|
tcg_gen_movi_tl(cpu_gpr[rd], 0);
|
||||||
|
}
|
||||||
opn = "xor";
|
opn = "xor";
|
||||||
break;
|
break;
|
||||||
case OPC_MUL:
|
}
|
||||||
tcg_gen_mul_tl(t0, t0, t1);
|
MIPS_DEBUG("%s %s, %s, %s", opn, regnames[rd], regnames[rs], regnames[rt]);
|
||||||
tcg_gen_ext32s_tl(t0, t0);
|
}
|
||||||
opn = "mul";
|
|
||||||
|
/* Set on lower than */
|
||||||
|
static void gen_slt (CPUState *env, uint32_t opc, int rd, int rs, int rt)
|
||||||
|
{
|
||||||
|
const char *opn = "slt";
|
||||||
|
TCGv t0, t1;
|
||||||
|
|
||||||
|
if (rd == 0) {
|
||||||
|
/* If no destination, treat it as a 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 OPC_SLT:
|
||||||
|
gen_op_lt(cpu_gpr[rd], t0, t1);
|
||||||
|
opn = "slt";
|
||||||
break;
|
break;
|
||||||
case OPC_MOVN:
|
case OPC_SLTU:
|
||||||
{
|
gen_op_ltu(cpu_gpr[rd], t0, t1);
|
||||||
int l1 = gen_new_label();
|
opn = "sltu";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
MIPS_DEBUG("%s %s, %s, %s", opn, regnames[rd], regnames[rs], regnames[rt]);
|
||||||
|
tcg_temp_free(t0);
|
||||||
|
tcg_temp_free(t1);
|
||||||
|
}
|
||||||
|
|
||||||
tcg_gen_brcondi_tl(TCG_COND_EQ, t1, 0, l1);
|
/* Shifts */
|
||||||
gen_store_gpr(t0, rd);
|
static void gen_shift (CPUState *env, DisasContext *ctx, uint32_t opc,
|
||||||
gen_set_label(l1);
|
int rd, int rs, int rt)
|
||||||
}
|
{
|
||||||
opn = "movn";
|
const char *opn = "shifts";
|
||||||
goto print;
|
TCGv t0, t1;
|
||||||
case OPC_MOVZ:
|
|
||||||
{
|
|
||||||
int l1 = gen_new_label();
|
|
||||||
|
|
||||||
tcg_gen_brcondi_tl(TCG_COND_NE, t1, 0, l1);
|
if (rd == 0) {
|
||||||
gen_store_gpr(t0, rd);
|
/* If no destination, treat it as a NOP.
|
||||||
gen_set_label(l1);
|
For add & sub, we must generate the overflow exception when needed. */
|
||||||
}
|
MIPS_DEBUG("NOP");
|
||||||
opn = "movz";
|
return;
|
||||||
goto print;
|
}
|
||||||
|
|
||||||
|
t0 = tcg_temp_new();
|
||||||
|
t1 = tcg_temp_new();
|
||||||
|
gen_load_gpr(t0, rs);
|
||||||
|
gen_load_gpr(t1, rt);
|
||||||
|
switch (opc) {
|
||||||
case OPC_SLLV:
|
case OPC_SLLV:
|
||||||
tcg_gen_andi_tl(t0, t0, 0x1f);
|
tcg_gen_andi_tl(t0, t0, 0x1f);
|
||||||
tcg_gen_shl_tl(t0, t1, t0);
|
tcg_gen_shl_tl(t0, t1, t0);
|
||||||
tcg_gen_ext32s_tl(t0, t0);
|
tcg_gen_ext32s_tl(cpu_gpr[rd], t0);
|
||||||
opn = "sllv";
|
opn = "sllv";
|
||||||
break;
|
break;
|
||||||
case OPC_SRAV:
|
case OPC_SRAV:
|
||||||
tcg_gen_ext32s_tl(t1, t1);
|
tcg_gen_ext32s_tl(t1, t1);
|
||||||
tcg_gen_andi_tl(t0, t0, 0x1f);
|
tcg_gen_andi_tl(t0, t0, 0x1f);
|
||||||
tcg_gen_sar_tl(t0, t1, t0);
|
tcg_gen_sar_tl(cpu_gpr[rd], t1, t0);
|
||||||
opn = "srav";
|
opn = "srav";
|
||||||
break;
|
break;
|
||||||
case OPC_SRLV:
|
case OPC_SRLV:
|
||||||
@ -1654,37 +1792,28 @@ static void gen_arith (CPUState *env, DisasContext *ctx, uint32_t opc,
|
|||||||
tcg_gen_ext32u_tl(t1, t1);
|
tcg_gen_ext32u_tl(t1, t1);
|
||||||
tcg_gen_andi_tl(t0, t0, 0x1f);
|
tcg_gen_andi_tl(t0, t0, 0x1f);
|
||||||
tcg_gen_shr_tl(t0, t1, t0);
|
tcg_gen_shr_tl(t0, t1, t0);
|
||||||
tcg_gen_ext32s_tl(t0, t0);
|
tcg_gen_ext32s_tl(cpu_gpr[rd], t0);
|
||||||
opn = "srlv";
|
opn = "srlv";
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
/* rotrv is decoded as srlv on non-R2 CPUs */
|
/* rotrv is decoded as srlv on non-R2 CPUs */
|
||||||
if (env->insn_flags & ISA_MIPS32R2) {
|
if (env->insn_flags & ISA_MIPS32R2) {
|
||||||
int l1 = gen_new_label();
|
TCGv_i32 t2 = tcg_temp_new_i32();
|
||||||
int l2 = gen_new_label();
|
TCGv_i32 t3 = tcg_temp_new_i32();
|
||||||
|
|
||||||
tcg_gen_andi_tl(t0, t0, 0x1f);
|
tcg_gen_trunc_tl_i32(t2, t0);
|
||||||
tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 0, l1);
|
tcg_gen_trunc_tl_i32(t3, t1);
|
||||||
{
|
tcg_gen_andi_i32(t2, t2, 0x1f);
|
||||||
TCGv_i32 r_tmp1 = tcg_temp_new_i32();
|
tcg_gen_rotr_i32(t2, t3, t2);
|
||||||
TCGv_i32 r_tmp2 = tcg_temp_new_i32();
|
tcg_gen_ext_i32_tl(cpu_gpr[rd], t2);
|
||||||
|
tcg_temp_free_i32(t2);
|
||||||
tcg_gen_trunc_tl_i32(r_tmp1, t0);
|
tcg_temp_free_i32(t3);
|
||||||
tcg_gen_trunc_tl_i32(r_tmp2, t1);
|
|
||||||
tcg_gen_rotr_i32(r_tmp1, r_tmp1, r_tmp2);
|
|
||||||
tcg_temp_free_i32(r_tmp1);
|
|
||||||
tcg_temp_free_i32(r_tmp2);
|
|
||||||
tcg_gen_br(l2);
|
|
||||||
}
|
|
||||||
gen_set_label(l1);
|
|
||||||
tcg_gen_mov_tl(t0, t1);
|
|
||||||
gen_set_label(l2);
|
|
||||||
opn = "rotrv";
|
opn = "rotrv";
|
||||||
} else {
|
} else {
|
||||||
tcg_gen_ext32u_tl(t1, t1);
|
tcg_gen_ext32u_tl(t1, t1);
|
||||||
tcg_gen_andi_tl(t0, t0, 0x1f);
|
tcg_gen_andi_tl(t0, t0, 0x1f);
|
||||||
tcg_gen_shr_tl(t0, t1, t0);
|
tcg_gen_shr_tl(t0, t1, t0);
|
||||||
tcg_gen_ext32s_tl(t0, t0);
|
tcg_gen_ext32s_tl(cpu_gpr[rd], t0);
|
||||||
opn = "srlv";
|
opn = "srlv";
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -1697,36 +1826,26 @@ static void gen_arith (CPUState *env, DisasContext *ctx, uint32_t opc,
|
|||||||
#if defined(TARGET_MIPS64)
|
#if defined(TARGET_MIPS64)
|
||||||
case OPC_DSLLV:
|
case OPC_DSLLV:
|
||||||
tcg_gen_andi_tl(t0, t0, 0x3f);
|
tcg_gen_andi_tl(t0, t0, 0x3f);
|
||||||
tcg_gen_shl_tl(t0, t1, t0);
|
tcg_gen_shl_tl(cpu_gpr[rd], t1, t0);
|
||||||
opn = "dsllv";
|
opn = "dsllv";
|
||||||
break;
|
break;
|
||||||
case OPC_DSRAV:
|
case OPC_DSRAV:
|
||||||
tcg_gen_andi_tl(t0, t0, 0x3f);
|
tcg_gen_andi_tl(t0, t0, 0x3f);
|
||||||
tcg_gen_sar_tl(t0, t1, t0);
|
tcg_gen_sar_tl(cpu_gpr[rd], t1, t0);
|
||||||
opn = "dsrav";
|
opn = "dsrav";
|
||||||
break;
|
break;
|
||||||
case OPC_DSRLV:
|
case OPC_DSRLV:
|
||||||
switch ((ctx->opcode >> 6) & 0x1f) {
|
switch ((ctx->opcode >> 6) & 0x1f) {
|
||||||
case 0:
|
case 0:
|
||||||
tcg_gen_andi_tl(t0, t0, 0x3f);
|
tcg_gen_andi_tl(t0, t0, 0x3f);
|
||||||
tcg_gen_shr_tl(t0, t1, t0);
|
tcg_gen_shr_tl(cpu_gpr[rd], t1, t0);
|
||||||
opn = "dsrlv";
|
opn = "dsrlv";
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
/* drotrv is decoded as dsrlv on non-R2 CPUs */
|
/* drotrv is decoded as dsrlv on non-R2 CPUs */
|
||||||
if (env->insn_flags & ISA_MIPS32R2) {
|
if (env->insn_flags & ISA_MIPS32R2) {
|
||||||
int l1 = gen_new_label();
|
|
||||||
int l2 = gen_new_label();
|
|
||||||
|
|
||||||
tcg_gen_andi_tl(t0, t0, 0x3f);
|
tcg_gen_andi_tl(t0, t0, 0x3f);
|
||||||
tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 0, l1);
|
tcg_gen_rotr_tl(cpu_gpr[rd], t1, t0);
|
||||||
{
|
|
||||||
tcg_gen_rotr_tl(t0, t1, t0);
|
|
||||||
tcg_gen_br(l2);
|
|
||||||
}
|
|
||||||
gen_set_label(l1);
|
|
||||||
tcg_gen_mov_tl(t0, t1);
|
|
||||||
gen_set_label(l2);
|
|
||||||
opn = "drotrv";
|
opn = "drotrv";
|
||||||
} else {
|
} else {
|
||||||
tcg_gen_andi_tl(t0, t0, 0x3f);
|
tcg_gen_andi_tl(t0, t0, 0x3f);
|
||||||
@ -1741,15 +1860,8 @@ static void gen_arith (CPUState *env, DisasContext *ctx, uint32_t opc,
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
default:
|
|
||||||
MIPS_INVAL(opn);
|
|
||||||
generate_exception(ctx, EXCP_RI);
|
|
||||||
goto out;
|
|
||||||
}
|
}
|
||||||
gen_store_gpr(t0, rd);
|
|
||||||
print:
|
|
||||||
MIPS_DEBUG("%s %s, %s, %s", opn, regnames[rd], regnames[rs], regnames[rt]);
|
MIPS_DEBUG("%s %s, %s, %s", opn, regnames[rd], regnames[rs], regnames[rt]);
|
||||||
out:
|
|
||||||
tcg_temp_free(t0);
|
tcg_temp_free(t0);
|
||||||
tcg_temp_free(t1);
|
tcg_temp_free(t1);
|
||||||
}
|
}
|
||||||
@ -7465,14 +7577,29 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
|
|||||||
case OPC_SRL ... OPC_SRA:
|
case OPC_SRL ... OPC_SRA:
|
||||||
gen_arith_imm(env, ctx, op1, rd, rt, sa);
|
gen_arith_imm(env, ctx, op1, rd, rt, sa);
|
||||||
break;
|
break;
|
||||||
case OPC_MOVZ ... OPC_MOVN:
|
case OPC_MOVN: /* Conditional move */
|
||||||
|
case OPC_MOVZ:
|
||||||
check_insn(env, ctx, ISA_MIPS4 | ISA_MIPS32);
|
check_insn(env, ctx, ISA_MIPS4 | ISA_MIPS32);
|
||||||
case OPC_SLLV: /* Arithmetic */
|
gen_cond_move(env, op1, rd, rs, rt);
|
||||||
case OPC_SRLV ... OPC_SRAV:
|
break;
|
||||||
case OPC_ADD ... OPC_NOR:
|
case OPC_ADD ... OPC_SUBU:
|
||||||
case OPC_SLT ... OPC_SLTU:
|
|
||||||
gen_arith(env, ctx, op1, rd, rs, rt);
|
gen_arith(env, ctx, op1, rd, rs, rt);
|
||||||
break;
|
break;
|
||||||
|
case OPC_SLLV: /* Shifts */
|
||||||
|
case OPC_SRLV:
|
||||||
|
case OPC_SRAV:
|
||||||
|
gen_shift(env, ctx, op1, rd, rs, rt);
|
||||||
|
break;
|
||||||
|
case OPC_SLT: /* Set on less than */
|
||||||
|
case OPC_SLTU:
|
||||||
|
gen_slt(env, op1, rd, rs, rt);
|
||||||
|
break;
|
||||||
|
case OPC_AND: /* Logic*/
|
||||||
|
case OPC_OR:
|
||||||
|
case OPC_NOR:
|
||||||
|
case OPC_XOR:
|
||||||
|
gen_logic(env, op1, rd, rs, rt);
|
||||||
|
break;
|
||||||
case OPC_MULT ... OPC_DIVU:
|
case OPC_MULT ... OPC_DIVU:
|
||||||
if (sa) {
|
if (sa) {
|
||||||
check_insn(env, ctx, INSN_VR54XX);
|
check_insn(env, ctx, INSN_VR54XX);
|
||||||
@ -7545,13 +7672,18 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
|
|||||||
check_mips_64(ctx);
|
check_mips_64(ctx);
|
||||||
gen_arith_imm(env, ctx, op1, rd, rt, sa);
|
gen_arith_imm(env, ctx, op1, rd, rt, sa);
|
||||||
break;
|
break;
|
||||||
case OPC_DSLLV:
|
|
||||||
case OPC_DSRLV ... OPC_DSRAV:
|
|
||||||
case OPC_DADD ... OPC_DSUBU:
|
case OPC_DADD ... OPC_DSUBU:
|
||||||
check_insn(env, ctx, ISA_MIPS3);
|
check_insn(env, ctx, ISA_MIPS3);
|
||||||
check_mips_64(ctx);
|
check_mips_64(ctx);
|
||||||
gen_arith(env, ctx, op1, rd, rs, rt);
|
gen_arith(env, ctx, op1, rd, rs, rt);
|
||||||
break;
|
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_DMULT ... OPC_DDIVU:
|
case OPC_DMULT ... OPC_DDIVU:
|
||||||
check_insn(env, ctx, ISA_MIPS3);
|
check_insn(env, ctx, ISA_MIPS3);
|
||||||
check_mips_64(ctx);
|
check_mips_64(ctx);
|
||||||
|
Loading…
Reference in New Issue
Block a user