target/mips: Implement emulation of nanoMIPS EVA instructions

Implement emulation of nanoMIPS EVA instructions. They are all
part of P.LS.E0 instruction pool, or one of its subpools.

Backports commit d046a9ea1b8877a570a8b12a2d0125ec59fe5b22 from qemu
This commit is contained in:
Dimitrije Nikolic 2018-11-10 12:16:17 -05:00 committed by Lioncash
parent 006f0a5873
commit 948d49db81
No known key found for this signature in database
GPG Key ID: 4E3C3CC1031BA9C7

View File

@ -2871,6 +2871,16 @@ static inline void check_dsp_r3(DisasContext *ctx)
}
}
/* This code generates a "reserved instruction" exception if the
CPU has corresponding flag set which indicates that the instruction
has been removed. */
static inline void check_insn_opc_removed(DisasContext *ctx, uint64_t flags)
{
if (unlikely(ctx->insn_flags & flags)) {
generate_exception_end(ctx, EXCP_RI);
}
}
/*
* The Linux kernel traps certain reserved instruction exceptions to
* emulate the corresponding instructions. QEMU is the kernel in user
@ -2895,16 +2905,6 @@ static inline void check_insn(DisasContext *ctx, uint64_t flags)
}
}
/* This code generates a "reserved instruction" exception if the
CPU has corresponding flag set which indicates that the instruction
has been removed. */
static inline void check_insn_opc_removed(DisasContext *ctx, uint64_t flags)
{
if (unlikely(ctx->insn_flags & flags)) {
generate_exception_end(ctx, EXCP_RI);
}
}
/* This code generates a "reserved instruction" exception if the
CPU does not support 64-bit paired-single (PS) floating point data type */
static inline void check_ps(DisasContext *ctx)
@ -3000,6 +3000,35 @@ static inline void check_nms(DisasContext *ctx)
}
}
/*
* This code generates a "reserved instruction" exception if the
* Config5 NMS bit is set, and Config1 DL, Config1 IL, Config2 SL,
* Config2 TL, and Config5 L2C are unset.
*/
static inline void check_nms_dl_il_sl_tl_l2c(DisasContext *ctx)
{
if (unlikely(ctx->CP0_Config5 & (1 << CP0C5_NMS)) &&
!(ctx->CP0_Config1 & (1 << CP0C1_DL)) &&
!(ctx->CP0_Config1 & (1 << CP0C1_IL)) &&
!(ctx->CP0_Config2 & (1 << CP0C2_SL)) &&
!(ctx->CP0_Config2 & (1 << CP0C2_TL)) &&
!(ctx->CP0_Config5 & (1 << CP0C5_L2C)))
{
generate_exception_end(ctx, EXCP_RI);
}
}
/*
* This code generates a "reserved instruction" exception if the
* Config5 EVA bit is NOT set.
*/
static inline void check_eva(DisasContext *ctx)
{
if (unlikely(!(ctx->CP0_Config5 & (1 << CP0C5_EVA)))) {
generate_exception_end(ctx, EXCP_RI);
}
}
/* Define small wrappers for gen_load_fpr* so that we have a uniform
calling interface for 32 and 64-bit FPRs. No sense in changing
@ -21362,6 +21391,105 @@ static int decode_nanomips_32_48_opc(CPUMIPSState *env, DisasContext *ctx)
break;
}
break;
case NM_P_LS_E0:
switch (extract32(ctx->opcode, 11, 4)) {
case NM_LBE:
check_eva(ctx);
check_cp0_enabled(ctx);
gen_ld(ctx, OPC_LBE, rt, rs, s);
break;
case NM_SBE:
check_eva(ctx);
check_cp0_enabled(ctx);
gen_st(ctx, OPC_SBE, rt, rs, s);
break;
case NM_LBUE:
check_eva(ctx);
check_cp0_enabled(ctx);
gen_ld(ctx, OPC_LBUE, rt, rs, s);
break;
case NM_P_PREFE:
if (rt == 31) {
/* case NM_SYNCIE */
check_eva(ctx);
check_cp0_enabled(ctx);
/* Break the TB to be able to sync copied instructions
immediately */
ctx->base.is_jmp = DISAS_STOP;
} else {
/* case NM_PREFE */
check_eva(ctx);
check_cp0_enabled(ctx);
/* Treat as NOP. */
}
break;
case NM_LHE:
check_eva(ctx);
check_cp0_enabled(ctx);
gen_ld(ctx, OPC_LHE, rt, rs, s);
break;
case NM_SHE:
check_eva(ctx);
check_cp0_enabled(ctx);
gen_st(ctx, OPC_SHE, rt, rs, s);
break;
case NM_LHUE:
check_eva(ctx);
check_cp0_enabled(ctx);
gen_ld(ctx, OPC_LHUE, rt, rs, s);
break;
case NM_CACHEE:
check_nms_dl_il_sl_tl_l2c(ctx);
gen_cache_operation(ctx, rt, rs, s);
break;
case NM_LWE:
check_eva(ctx);
check_cp0_enabled(ctx);
gen_ld(ctx, OPC_LWE, rt, rs, s);
break;
case NM_SWE:
check_eva(ctx);
check_cp0_enabled(ctx);
gen_st(ctx, OPC_SWE, rt, rs, s);
break;
case NM_P_LLE:
switch (extract32(ctx->opcode, 2, 2)) {
case NM_LLE:
check_xnp(ctx);
check_eva(ctx);
check_cp0_enabled(ctx);
gen_ld(ctx, OPC_LLE, rt, rs, s);
break;
case NM_LLWPE:
check_xnp(ctx);
check_eva(ctx);
check_cp0_enabled(ctx);
gen_llwp(ctx, rs, 0, rt, extract32(ctx->opcode, 3, 5));
default:
generate_exception_end(ctx, EXCP_RI);
break;
}
break;
case NM_P_SCE:
switch (extract32(ctx->opcode, 2, 2)) {
case NM_SCE:
check_xnp(ctx);
check_eva(ctx);
check_cp0_enabled(ctx);
gen_st_cond(ctx, OPC_SCE, rt, rs, s);
break;
case NM_SCWPE:
check_xnp(ctx);
check_eva(ctx);
check_cp0_enabled(ctx);
gen_scwp(ctx, rs, 0, rt, extract32(ctx->opcode, 3, 5));
default:
generate_exception_end(ctx, EXCP_RI);
break;
}
break;
}
break;
case NM_P_LS_WM:
case NM_P_LS_UAWM:
check_nms(ctx);