Commit 8bf6cbaf authored by Laurent Vivier's avatar Laurent Vivier
Browse files

target/m68k: add chk and chk2



chk and chk2 compare a value to boundaries, and
trigger a CHK exception if the value is out of bounds.

Signed-off-by: default avatarLaurent Vivier <laurent@vivier.eu>
Suggested-by: default avatarRichard Henderson <richard.henderson@linaro.org>
Reviewed-by: default avatarRichard Henderson <richard.henderson@linaro.org>
Message-Id: <20180104012913.30763-8-laurent@vivier.eu>
parent d2f8fb8e
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -2985,6 +2985,13 @@ void cpu_loop(CPUM68KState *env)
            info._sifields._sigfault._addr = env->pc;
            queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
            break;
        case EXCP_CHK:
            info.si_signo = TARGET_SIGFPE;
            info.si_errno = 0;
            info.si_code = TARGET_FPE_INTOVF;
            info._sifields._sigfault._addr = env->pc;
            queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
            break;
        case EXCP_DIV0:
            info.si_signo = TARGET_SIGFPE;
            info.si_errno = 0;
+2 −0
Original line number Diff line number Diff line
@@ -134,6 +134,7 @@ static void m68020_cpu_initfn(Object *obj)
    m68k_set_feature(env, M68K_FEATURE_CAS);
    m68k_set_feature(env, M68K_FEATURE_BKPT);
    m68k_set_feature(env, M68K_FEATURE_RTD);
    m68k_set_feature(env, M68K_FEATURE_CHK2);
}
#define m68030_cpu_initfn m68020_cpu_initfn
#define m68040_cpu_initfn m68020_cpu_initfn
@@ -156,6 +157,7 @@ static void m68060_cpu_initfn(Object *obj)
    m68k_set_feature(env, M68K_FEATURE_CAS);
    m68k_set_feature(env, M68K_FEATURE_BKPT);
    m68k_set_feature(env, M68K_FEATURE_RTD);
    m68k_set_feature(env, M68K_FEATURE_CHK2);
}

static void m5208_cpu_initfn(Object *obj)
+1 −0
Original line number Diff line number Diff line
@@ -305,6 +305,7 @@ enum m68k_features {
    M68K_FEATURE_CAS,
    M68K_FEATURE_BKPT,
    M68K_FEATURE_RTD,
    M68K_FEATURE_CHK2,
};

static inline int m68k_feature(CPUM68KState *env, int feature)
+3 −0
Original line number Diff line number Diff line
@@ -94,3 +94,6 @@ DEF_HELPER_FLAGS_4(bfchg_mem, TCG_CALL_NO_WG, i32, env, i32, s32, i32)
DEF_HELPER_FLAGS_4(bfclr_mem, TCG_CALL_NO_WG, i32, env, i32, s32, i32)
DEF_HELPER_FLAGS_4(bfset_mem, TCG_CALL_NO_WG, i32, env, i32, s32, i32)
DEF_HELPER_FLAGS_4(bfffo_mem, TCG_CALL_NO_WG, i64, env, i32, s32, i32)

DEF_HELPER_3(chk, void, env, s32, s32)
DEF_HELPER_4(chk2, void, env, s32, s32, s32)
+61 −0
Original line number Diff line number Diff line
@@ -947,3 +947,64 @@ uint64_t HELPER(bfffo_mem)(CPUM68KState *env, uint32_t addr,
       is already zero.  */
    return n | ffo;
}

void HELPER(chk)(CPUM68KState *env, int32_t val, int32_t ub)
{
    /* From the specs:
     *   X: Not affected, C,V,Z: Undefined,
     *   N: Set if val < 0; cleared if val > ub, undefined otherwise
     * We implement here values found from a real MC68040:
     *   X,V,Z: Not affected
     *   N: Set if val < 0; cleared if val >= 0
     *   C: if 0 <= ub: set if val < 0 or val > ub, cleared otherwise
     *      if 0 > ub: set if val > ub and val < 0, cleared otherwise
     */
    env->cc_n = val;
    env->cc_c = 0 <= ub ? val < 0 || val > ub : val > ub && val < 0;

    if (val < 0 || val > ub) {
        CPUState *cs = CPU(m68k_env_get_cpu(env));

        /* Recover PC and CC_OP for the beginning of the insn.  */
        cpu_restore_state(cs, GETPC());

        /* flags have been modified by gen_flush_flags() */
        env->cc_op = CC_OP_FLAGS;
        /* Adjust PC to end of the insn.  */
        env->pc += 2;

        cs->exception_index = EXCP_CHK;
        cpu_loop_exit(cs);
    }
}

void HELPER(chk2)(CPUM68KState *env, int32_t val, int32_t lb, int32_t ub)
{
    /* From the specs:
     *   X: Not affected, N,V: Undefined,
     *   Z: Set if val is equal to lb or ub
     *   C: Set if val < lb or val > ub, cleared otherwise
     * We implement here values found from a real MC68040:
     *   X,N,V: Not affected
     *   Z: Set if val is equal to lb or ub
     *   C: if lb <= ub: set if val < lb or val > ub, cleared otherwise
     *      if lb > ub: set if val > ub and val < lb, cleared otherwise
     */
    env->cc_z = val != lb && val != ub;
    env->cc_c = lb <= ub ? val < lb || val > ub : val > ub && val < lb;

    if (env->cc_c) {
        CPUState *cs = CPU(m68k_env_get_cpu(env));

        /* Recover PC and CC_OP for the beginning of the insn.  */
        cpu_restore_state(cs, GETPC());

        /* flags have been modified by gen_flush_flags() */
        env->cc_op = CC_OP_FLAGS;
        /* Adjust PC to end of the insn.  */
        env->pc += 4;

        cs->exception_index = EXCP_CHK;
        cpu_loop_exit(cs);
    }
}
Loading