mirror of https://github.com/xemu-project/xemu.git
target-mips: add MSA branch instructions
add MSA branch instructions Reviewed-by: James Hogan <james.hogan@imgtec.com> Signed-off-by: Yongbok Kim <yongbok.kim@imgtec.com> Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
This commit is contained in:
parent
42daa9bed4
commit
5692c6e1f8
|
@ -17247,6 +17247,93 @@ static inline int check_msa_access(DisasContext *ctx)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void gen_check_zero_element(TCGv tresult, uint8_t df, uint8_t wt)
|
||||||
|
{
|
||||||
|
/* generates tcg ops to check if any element is 0 */
|
||||||
|
/* Note this function only works with MSA_WRLEN = 128 */
|
||||||
|
uint64_t eval_zero_or_big = 0;
|
||||||
|
uint64_t eval_big = 0;
|
||||||
|
TCGv_i64 t0 = tcg_temp_new_i64();
|
||||||
|
TCGv_i64 t1 = tcg_temp_new_i64();
|
||||||
|
switch (df) {
|
||||||
|
case DF_BYTE:
|
||||||
|
eval_zero_or_big = 0x0101010101010101ULL;
|
||||||
|
eval_big = 0x8080808080808080ULL;
|
||||||
|
break;
|
||||||
|
case DF_HALF:
|
||||||
|
eval_zero_or_big = 0x0001000100010001ULL;
|
||||||
|
eval_big = 0x8000800080008000ULL;
|
||||||
|
break;
|
||||||
|
case DF_WORD:
|
||||||
|
eval_zero_or_big = 0x0000000100000001ULL;
|
||||||
|
eval_big = 0x8000000080000000ULL;
|
||||||
|
break;
|
||||||
|
case DF_DOUBLE:
|
||||||
|
eval_zero_or_big = 0x0000000000000001ULL;
|
||||||
|
eval_big = 0x8000000000000000ULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
tcg_gen_subi_i64(t0, msa_wr_d[wt<<1], eval_zero_or_big);
|
||||||
|
tcg_gen_andc_i64(t0, t0, msa_wr_d[wt<<1]);
|
||||||
|
tcg_gen_andi_i64(t0, t0, eval_big);
|
||||||
|
tcg_gen_subi_i64(t1, msa_wr_d[(wt<<1)+1], eval_zero_or_big);
|
||||||
|
tcg_gen_andc_i64(t1, t1, msa_wr_d[(wt<<1)+1]);
|
||||||
|
tcg_gen_andi_i64(t1, t1, eval_big);
|
||||||
|
tcg_gen_or_i64(t0, t0, t1);
|
||||||
|
/* if all bits are zero then all elements are not zero */
|
||||||
|
/* if some bit is non-zero then some element is zero */
|
||||||
|
tcg_gen_setcondi_i64(TCG_COND_NE, t0, t0, 0);
|
||||||
|
tcg_gen_trunc_i64_tl(tresult, t0);
|
||||||
|
tcg_temp_free_i64(t0);
|
||||||
|
tcg_temp_free_i64(t1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gen_msa_branch(CPUMIPSState *env, DisasContext *ctx, uint32_t op1)
|
||||||
|
{
|
||||||
|
uint8_t df = (ctx->opcode >> 21) & 0x3;
|
||||||
|
uint8_t wt = (ctx->opcode >> 16) & 0x1f;
|
||||||
|
int64_t s16 = (int16_t)ctx->opcode;
|
||||||
|
|
||||||
|
check_msa_access(ctx);
|
||||||
|
|
||||||
|
if (ctx->insn_flags & ISA_MIPS32R6 && ctx->hflags & MIPS_HFLAG_BMASK) {
|
||||||
|
MIPS_DEBUG("CTI in delay / forbidden slot");
|
||||||
|
generate_exception(ctx, EXCP_RI);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch (op1) {
|
||||||
|
case OPC_BZ_V:
|
||||||
|
case OPC_BNZ_V:
|
||||||
|
{
|
||||||
|
TCGv_i64 t0 = tcg_temp_new_i64();
|
||||||
|
tcg_gen_or_i64(t0, msa_wr_d[wt<<1], msa_wr_d[(wt<<1)+1]);
|
||||||
|
tcg_gen_setcondi_i64((op1 == OPC_BZ_V) ?
|
||||||
|
TCG_COND_EQ : TCG_COND_NE, t0, t0, 0);
|
||||||
|
tcg_gen_trunc_i64_tl(bcond, t0);
|
||||||
|
tcg_temp_free_i64(t0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OPC_BZ_B:
|
||||||
|
case OPC_BZ_H:
|
||||||
|
case OPC_BZ_W:
|
||||||
|
case OPC_BZ_D:
|
||||||
|
gen_check_zero_element(bcond, df, wt);
|
||||||
|
break;
|
||||||
|
case OPC_BNZ_B:
|
||||||
|
case OPC_BNZ_H:
|
||||||
|
case OPC_BNZ_W:
|
||||||
|
case OPC_BNZ_D:
|
||||||
|
gen_check_zero_element(bcond, df, wt);
|
||||||
|
tcg_gen_setcondi_tl(TCG_COND_EQ, bcond, bcond, 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->btarget = ctx->pc + (s16 << 2) + 4;
|
||||||
|
|
||||||
|
ctx->hflags |= MIPS_HFLAG_BC;
|
||||||
|
ctx->hflags |= MIPS_HFLAG_BDS32;
|
||||||
|
}
|
||||||
|
|
||||||
static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
|
static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
|
||||||
{
|
{
|
||||||
int32_t offset;
|
int32_t offset;
|
||||||
|
@ -17568,133 +17655,152 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OPC_CP1:
|
case OPC_CP1:
|
||||||
if (ctx->CP0_Config1 & (1 << CP0C1_FP)) {
|
op1 = MASK_CP1(ctx->opcode);
|
||||||
|
|
||||||
|
switch (op1) {
|
||||||
|
case OPC_MFHC1:
|
||||||
|
case OPC_MTHC1:
|
||||||
check_cp1_enabled(ctx);
|
check_cp1_enabled(ctx);
|
||||||
op1 = MASK_CP1(ctx->opcode);
|
check_insn(ctx, ISA_MIPS32R2);
|
||||||
switch (op1) {
|
case OPC_MFC1:
|
||||||
case OPC_MFHC1:
|
case OPC_CFC1:
|
||||||
case OPC_MTHC1:
|
case OPC_MTC1:
|
||||||
check_insn(ctx, ISA_MIPS32R2);
|
case OPC_CTC1:
|
||||||
case OPC_MFC1:
|
check_cp1_enabled(ctx);
|
||||||
case OPC_CFC1:
|
gen_cp1(ctx, op1, rt, rd);
|
||||||
case OPC_MTC1:
|
break;
|
||||||
case OPC_CTC1:
|
|
||||||
gen_cp1(ctx, op1, rt, rd);
|
|
||||||
break;
|
|
||||||
#if defined(TARGET_MIPS64)
|
#if defined(TARGET_MIPS64)
|
||||||
case OPC_DMFC1:
|
case OPC_DMFC1:
|
||||||
case OPC_DMTC1:
|
case OPC_DMTC1:
|
||||||
check_insn(ctx, ISA_MIPS3);
|
check_cp1_enabled(ctx);
|
||||||
gen_cp1(ctx, op1, rt, rd);
|
check_insn(ctx, ISA_MIPS3);
|
||||||
break;
|
gen_cp1(ctx, op1, rt, rd);
|
||||||
|
break;
|
||||||
#endif
|
#endif
|
||||||
case OPC_BC1EQZ: /* OPC_BC1ANY2 */
|
case OPC_BC1EQZ: /* OPC_BC1ANY2 */
|
||||||
if (ctx->insn_flags & ISA_MIPS32R6) {
|
check_cp1_enabled(ctx);
|
||||||
/* OPC_BC1EQZ */
|
if (ctx->insn_flags & ISA_MIPS32R6) {
|
||||||
gen_compute_branch1_r6(ctx, MASK_CP1(ctx->opcode),
|
/* OPC_BC1EQZ */
|
||||||
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),
|
gen_compute_branch1_r6(ctx, MASK_CP1(ctx->opcode),
|
||||||
rt, imm << 2);
|
rt, imm << 2);
|
||||||
break;
|
} else {
|
||||||
case OPC_BC1ANY4:
|
/* OPC_BC1ANY2 */
|
||||||
check_insn_opc_removed(ctx, ISA_MIPS32R6);
|
|
||||||
check_cop1x(ctx);
|
check_cop1x(ctx);
|
||||||
check_insn(ctx, ASE_MIPS3D);
|
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),
|
gen_compute_branch1(ctx, MASK_BC1(ctx->opcode),
|
||||||
(rt >> 2) & 0x7, imm << 2);
|
(rt >> 2) & 0x7, imm << 2);
|
||||||
break;
|
}
|
||||||
case OPC_PS_FMT:
|
break;
|
||||||
check_insn_opc_removed(ctx, ISA_MIPS32R6);
|
case OPC_BC1NEZ:
|
||||||
case OPC_S_FMT:
|
check_cp1_enabled(ctx);
|
||||||
case OPC_D_FMT:
|
check_insn(ctx, ISA_MIPS32R6);
|
||||||
gen_farith(ctx, ctx->opcode & FOP(0x3f, 0x1f), rt, rd, sa,
|
gen_compute_branch1_r6(ctx, MASK_CP1(ctx->opcode),
|
||||||
(imm >> 8) & 0x7);
|
rt, imm << 2);
|
||||||
break;
|
break;
|
||||||
case OPC_W_FMT:
|
case OPC_BC1ANY4:
|
||||||
case OPC_L_FMT:
|
check_cp1_enabled(ctx);
|
||||||
{
|
check_insn_opc_removed(ctx, ISA_MIPS32R6);
|
||||||
int r6_op = ctx->opcode & FOP(0x3f, 0x1f);
|
check_cop1x(ctx);
|
||||||
if (ctx->insn_flags & ISA_MIPS32R6) {
|
check_insn(ctx, ASE_MIPS3D);
|
||||||
switch (r6_op) {
|
/* fall through */
|
||||||
case R6_OPC_CMP_AF_S:
|
case OPC_BC1:
|
||||||
case R6_OPC_CMP_UN_S:
|
check_cp1_enabled(ctx);
|
||||||
case R6_OPC_CMP_EQ_S:
|
check_insn_opc_removed(ctx, ISA_MIPS32R6);
|
||||||
case R6_OPC_CMP_UEQ_S:
|
gen_compute_branch1(ctx, MASK_BC1(ctx->opcode),
|
||||||
case R6_OPC_CMP_LT_S:
|
(rt >> 2) & 0x7, imm << 2);
|
||||||
case R6_OPC_CMP_ULT_S:
|
break;
|
||||||
case R6_OPC_CMP_LE_S:
|
case OPC_PS_FMT:
|
||||||
case R6_OPC_CMP_ULE_S:
|
check_cp1_enabled(ctx);
|
||||||
case R6_OPC_CMP_SAF_S:
|
check_insn_opc_removed(ctx, ISA_MIPS32R6);
|
||||||
case R6_OPC_CMP_SUN_S:
|
case OPC_S_FMT:
|
||||||
case R6_OPC_CMP_SEQ_S:
|
case OPC_D_FMT:
|
||||||
case R6_OPC_CMP_SEUQ_S:
|
check_cp1_enabled(ctx);
|
||||||
case R6_OPC_CMP_SLT_S:
|
gen_farith(ctx, ctx->opcode & FOP(0x3f, 0x1f), rt, rd, sa,
|
||||||
case R6_OPC_CMP_SULT_S:
|
(imm >> 8) & 0x7);
|
||||||
case R6_OPC_CMP_SLE_S:
|
break;
|
||||||
case R6_OPC_CMP_SULE_S:
|
case OPC_W_FMT:
|
||||||
case R6_OPC_CMP_OR_S:
|
case OPC_L_FMT:
|
||||||
case R6_OPC_CMP_UNE_S:
|
{
|
||||||
case R6_OPC_CMP_NE_S:
|
int r6_op = ctx->opcode & FOP(0x3f, 0x1f);
|
||||||
case R6_OPC_CMP_SOR_S:
|
check_cp1_enabled(ctx);
|
||||||
case R6_OPC_CMP_SUNE_S:
|
if (ctx->insn_flags & ISA_MIPS32R6) {
|
||||||
case R6_OPC_CMP_SNE_S:
|
switch (r6_op) {
|
||||||
gen_r6_cmp_s(ctx, ctx->opcode & 0x1f, rt, rd, sa);
|
case R6_OPC_CMP_AF_S:
|
||||||
break;
|
case R6_OPC_CMP_UN_S:
|
||||||
case R6_OPC_CMP_AF_D:
|
case R6_OPC_CMP_EQ_S:
|
||||||
case R6_OPC_CMP_UN_D:
|
case R6_OPC_CMP_UEQ_S:
|
||||||
case R6_OPC_CMP_EQ_D:
|
case R6_OPC_CMP_LT_S:
|
||||||
case R6_OPC_CMP_UEQ_D:
|
case R6_OPC_CMP_ULT_S:
|
||||||
case R6_OPC_CMP_LT_D:
|
case R6_OPC_CMP_LE_S:
|
||||||
case R6_OPC_CMP_ULT_D:
|
case R6_OPC_CMP_ULE_S:
|
||||||
case R6_OPC_CMP_LE_D:
|
case R6_OPC_CMP_SAF_S:
|
||||||
case R6_OPC_CMP_ULE_D:
|
case R6_OPC_CMP_SUN_S:
|
||||||
case R6_OPC_CMP_SAF_D:
|
case R6_OPC_CMP_SEQ_S:
|
||||||
case R6_OPC_CMP_SUN_D:
|
case R6_OPC_CMP_SEUQ_S:
|
||||||
case R6_OPC_CMP_SEQ_D:
|
case R6_OPC_CMP_SLT_S:
|
||||||
case R6_OPC_CMP_SEUQ_D:
|
case R6_OPC_CMP_SULT_S:
|
||||||
case R6_OPC_CMP_SLT_D:
|
case R6_OPC_CMP_SLE_S:
|
||||||
case R6_OPC_CMP_SULT_D:
|
case R6_OPC_CMP_SULE_S:
|
||||||
case R6_OPC_CMP_SLE_D:
|
case R6_OPC_CMP_OR_S:
|
||||||
case R6_OPC_CMP_SULE_D:
|
case R6_OPC_CMP_UNE_S:
|
||||||
case R6_OPC_CMP_OR_D:
|
case R6_OPC_CMP_NE_S:
|
||||||
case R6_OPC_CMP_UNE_D:
|
case R6_OPC_CMP_SOR_S:
|
||||||
case R6_OPC_CMP_NE_D:
|
case R6_OPC_CMP_SUNE_S:
|
||||||
case R6_OPC_CMP_SOR_D:
|
case R6_OPC_CMP_SNE_S:
|
||||||
case R6_OPC_CMP_SUNE_D:
|
gen_r6_cmp_s(ctx, ctx->opcode & 0x1f, rt, rd, sa);
|
||||||
case R6_OPC_CMP_SNE_D:
|
break;
|
||||||
gen_r6_cmp_d(ctx, ctx->opcode & 0x1f, rt, rd, sa);
|
case R6_OPC_CMP_AF_D:
|
||||||
break;
|
case R6_OPC_CMP_UN_D:
|
||||||
default:
|
case R6_OPC_CMP_EQ_D:
|
||||||
gen_farith(ctx, ctx->opcode & FOP(0x3f, 0x1f), rt, rd, sa,
|
case R6_OPC_CMP_UEQ_D:
|
||||||
(imm >> 8) & 0x7);
|
case R6_OPC_CMP_LT_D:
|
||||||
break;
|
case R6_OPC_CMP_ULT_D:
|
||||||
}
|
case R6_OPC_CMP_LE_D:
|
||||||
} else {
|
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,
|
gen_farith(ctx, ctx->opcode & FOP(0x3f, 0x1f), rt, rd, sa,
|
||||||
(imm >> 8) & 0x7);
|
(imm >> 8) & 0x7);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
} else {
|
||||||
|
gen_farith(ctx, ctx->opcode & FOP(0x3f, 0x1f), rt, rd, sa,
|
||||||
|
(imm >> 8) & 0x7);
|
||||||
}
|
}
|
||||||
default:
|
break;
|
||||||
MIPS_INVAL("cp1");
|
}
|
||||||
generate_exception (ctx, EXCP_RI);
|
case OPC_BZ_V:
|
||||||
break;
|
case OPC_BNZ_V:
|
||||||
}
|
case OPC_BZ_B:
|
||||||
} else {
|
case OPC_BZ_H:
|
||||||
generate_exception_err(ctx, EXCP_CpU, 1);
|
case OPC_BZ_W:
|
||||||
|
case OPC_BZ_D:
|
||||||
|
case OPC_BNZ_B:
|
||||||
|
case OPC_BNZ_H:
|
||||||
|
case OPC_BNZ_W:
|
||||||
|
case OPC_BNZ_D:
|
||||||
|
check_insn(ctx, ASE_MSA);
|
||||||
|
gen_msa_branch(env, ctx, op1);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
MIPS_INVAL("cp1");
|
||||||
|
generate_exception(ctx, EXCP_RI);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue