Commit d046a9ea authored by Dimitrije Nikolic's avatar Dimitrije Nikolic Committed by Aleksandar Markovic
Browse files

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.

Reviewed-by: default avatarStefan Markovic <smarkovic@wavecomp.com>
Signed-off-by: default avatarDimitrije Nikolic <dnikolic@wavecomp.com>
Signed-off-by: default avatarAleksandar Markovic <amarkovic@wavecomp.com>
parent ba1e8117
Loading
Loading
Loading
Loading
+128 −0
Original line number Diff line number Diff line
@@ -2989,6 +2989,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
@@ -21218,6 +21247,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);