mirror of
https://github.com/yuzu-emu/unicorn.git
synced 2025-02-02 06:21:01 +00:00
target/mips: Add emulation of misc nanoMIPS instructions (pool32a0)
Add emulation of nanoMIPS instructions that are situated in pool32a0. Backports commit e0cf0e6586d6a2c7e56b58bdfb5a67cec04c2999 from qemu
This commit is contained in:
parent
aee648c5ee
commit
a2ff65acec
|
@ -16975,6 +16975,182 @@ static void gen_pool16c_nanomips_insn(DisasContext *ctx)
|
|||
}
|
||||
}
|
||||
|
||||
static void gen_pool32a0_nanomips_insn(DisasContext *ctx)
|
||||
{
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
int rt = extract32(ctx->opcode, 21, 5);
|
||||
int rs = extract32(ctx->opcode, 16, 5);
|
||||
int rd = extract32(ctx->opcode, 11, 5);
|
||||
|
||||
switch (extract32(ctx->opcode, 3, 7)) {
|
||||
case NM_P_TRAP:
|
||||
switch (extract32(ctx->opcode, 10, 1)) {
|
||||
case NM_TEQ:
|
||||
gen_trap(ctx, OPC_TEQ, rs, rt, -1);
|
||||
break;
|
||||
case NM_TNE:
|
||||
gen_trap(ctx, OPC_TNE, rs, rt, -1);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case NM_RDHWR:
|
||||
gen_rdhwr(ctx, rt, rs, extract32(ctx->opcode, 11, 3));
|
||||
break;
|
||||
case NM_SEB:
|
||||
gen_bshfl(ctx, OPC_SEB, rs, rt);
|
||||
break;
|
||||
case NM_SEH:
|
||||
gen_bshfl(ctx, OPC_SEH, rs, rt);
|
||||
break;
|
||||
case NM_SLLV:
|
||||
gen_shift(ctx, OPC_SLLV, rd, rt, rs);
|
||||
break;
|
||||
case NM_SRLV:
|
||||
gen_shift(ctx, OPC_SRLV, rd, rt, rs);
|
||||
break;
|
||||
case NM_SRAV:
|
||||
gen_shift(ctx, OPC_SRAV, rd, rt, rs);
|
||||
break;
|
||||
case NM_ROTRV:
|
||||
gen_shift(ctx, OPC_ROTRV, rd, rt, rs);
|
||||
break;
|
||||
case NM_ADD:
|
||||
gen_arith(ctx, OPC_ADD, rd, rs, rt);
|
||||
break;
|
||||
case NM_ADDU:
|
||||
gen_arith(ctx, OPC_ADDU, rd, rs, rt);
|
||||
break;
|
||||
case NM_SUB:
|
||||
gen_arith(ctx, OPC_SUB, rd, rs, rt);
|
||||
break;
|
||||
case NM_SUBU:
|
||||
gen_arith(ctx, OPC_SUBU, rd, rs, rt);
|
||||
break;
|
||||
case NM_P_CMOVE:
|
||||
switch (extract32(ctx->opcode, 10, 1)) {
|
||||
case NM_MOVZ:
|
||||
gen_cond_move(ctx, OPC_MOVZ, rd, rs, rt);
|
||||
break;
|
||||
case NM_MOVN:
|
||||
gen_cond_move(ctx, OPC_MOVN, rd, rs, rt);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case NM_AND:
|
||||
gen_logic(ctx, OPC_AND, rd, rs, rt);
|
||||
break;
|
||||
case NM_OR:
|
||||
gen_logic(ctx, OPC_OR, rd, rs, rt);
|
||||
break;
|
||||
case NM_NOR:
|
||||
gen_logic(ctx, OPC_NOR, rd, rs, rt);
|
||||
break;
|
||||
case NM_XOR:
|
||||
gen_logic(ctx, OPC_XOR, rd, rs, rt);
|
||||
break;
|
||||
case NM_SLT:
|
||||
gen_slt(ctx, OPC_SLT, rd, rs, rt);
|
||||
break;
|
||||
case NM_P_SLTU:
|
||||
if (rd == 0) {
|
||||
/* P_DVP */
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
TCGv t0 = tcg_temp_new(tcg_ctx);
|
||||
switch (extract32(ctx->opcode, 10, 1)) {
|
||||
case NM_DVP:
|
||||
if (ctx->vp) {
|
||||
check_cp0_enabled(ctx);
|
||||
gen_helper_dvp(tcg_ctx, t0, tcg_ctx->cpu_env);
|
||||
gen_store_gpr(tcg_ctx, t0, rt);
|
||||
}
|
||||
break;
|
||||
case NM_EVP:
|
||||
if (ctx->vp) {
|
||||
check_cp0_enabled(ctx);
|
||||
gen_helper_evp(tcg_ctx, t0, tcg_ctx->cpu_env);
|
||||
gen_store_gpr(tcg_ctx, t0, rt);
|
||||
}
|
||||
break;
|
||||
}
|
||||
tcg_temp_free(tcg_ctx, t0);
|
||||
#endif
|
||||
} else {
|
||||
gen_slt(ctx, OPC_SLTU, rd, rs, rt);
|
||||
}
|
||||
break;
|
||||
case NM_SOV:
|
||||
{
|
||||
TCGv t0 = tcg_temp_new(tcg_ctx);
|
||||
TCGv t1 = tcg_temp_new(tcg_ctx);
|
||||
TCGv t2 = tcg_temp_new(tcg_ctx);
|
||||
|
||||
gen_load_gpr(ctx, t1, rs);
|
||||
gen_load_gpr(ctx, t2, rt);
|
||||
tcg_gen_add_tl(tcg_ctx, t0, t1, t2);
|
||||
tcg_gen_ext32s_tl(tcg_ctx, t0, t0);
|
||||
tcg_gen_xor_tl(tcg_ctx, t1, t1, t2);
|
||||
tcg_gen_xor_tl(tcg_ctx, t2, t0, t2);
|
||||
tcg_gen_andc_tl(tcg_ctx, t1, t2, t1);
|
||||
|
||||
/* operands of same sign, result different sign */
|
||||
tcg_gen_setcondi_tl(tcg_ctx, TCG_COND_LT, t0, t1, 0);
|
||||
gen_store_gpr(tcg_ctx, t0, rd);
|
||||
|
||||
tcg_temp_free(tcg_ctx, t0);
|
||||
tcg_temp_free(tcg_ctx, t1);
|
||||
tcg_temp_free(tcg_ctx, t2);
|
||||
}
|
||||
break;
|
||||
case NM_MUL:
|
||||
gen_r6_muldiv(ctx, R6_OPC_MUL, rd, rs, rt);
|
||||
break;
|
||||
case NM_MUH:
|
||||
gen_r6_muldiv(ctx, R6_OPC_MUH, rd, rs, rt);
|
||||
break;
|
||||
case NM_MULU:
|
||||
gen_r6_muldiv(ctx, R6_OPC_MULU, rd, rs, rt);
|
||||
break;
|
||||
case NM_MUHU:
|
||||
gen_r6_muldiv(ctx, R6_OPC_MUHU, rd, rs, rt);
|
||||
break;
|
||||
case NM_DIV:
|
||||
gen_r6_muldiv(ctx, R6_OPC_DIV, rd, rs, rt);
|
||||
break;
|
||||
case NM_MOD:
|
||||
gen_r6_muldiv(ctx, R6_OPC_MOD, rd, rs, rt);
|
||||
break;
|
||||
case NM_DIVU:
|
||||
gen_r6_muldiv(ctx, R6_OPC_DIVU, rd, rs, rt);
|
||||
break;
|
||||
case NM_MODU:
|
||||
gen_r6_muldiv(ctx, R6_OPC_MODU, rd, rs, rt);
|
||||
break;
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
case NM_MFC0:
|
||||
check_cp0_enabled(ctx);
|
||||
if (rt == 0) {
|
||||
/* Treat as NOP. */
|
||||
break;
|
||||
}
|
||||
gen_mfc0(ctx, tcg_ctx->cpu_gpr[rt], rs, extract32(ctx->opcode, 11, 3));
|
||||
break;
|
||||
case NM_MTC0:
|
||||
check_cp0_enabled(ctx);
|
||||
{
|
||||
TCGv t0 = tcg_temp_new(tcg_ctx);
|
||||
|
||||
gen_load_gpr(ctx, t0, rt);
|
||||
gen_mtc0(ctx, t0, rs, extract32(ctx->opcode, 11, 3));
|
||||
tcg_temp_free(tcg_ctx, t0);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
generate_exception_end(ctx, EXCP_RI);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void gen_pool32f_nanomips_insn(DisasContext *ctx)
|
||||
{
|
||||
int rt, rs, rd;
|
||||
|
@ -17342,6 +17518,16 @@ static int decode_nanomips_32_48_opc(CPUMIPSState *env, DisasContext *ctx)
|
|||
}
|
||||
break;
|
||||
case NM_POOL32A:
|
||||
switch (ctx->opcode & 0x07) {
|
||||
case NM_POOL32A0:
|
||||
gen_pool32a0_nanomips_insn(ctx);
|
||||
break;
|
||||
case NM_POOL32A7:
|
||||
break;
|
||||
default:
|
||||
generate_exception_end(ctx, EXCP_RI);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case NM_P_GP_W:
|
||||
switch (ctx->opcode & 0x03) {
|
||||
|
|
Loading…
Reference in a new issue