diff mbox

[v7,07/17] target/m68k: add chk and chk2

Message ID 20180104012913.30763-8-laurent@vivier.eu (mailing list archive)
State New, archived
Headers show

Commit Message

Laurent Vivier Jan. 4, 2018, 1:29 a.m. UTC
chk and chk2 compare a value to boundaries, and
trigger a CHK exception if the value is out of bounds.

Signed-off-by: Laurent Vivier <laurent@vivier.eu>
Suggested-by: Richard Henderson <richard.henderson@linaro.org>
---

Notes:
    v7: chk: always update C and N flags
        add some comments
        move flush_flags() from the helper to the
        code generator, because otherwise we need
        to do an update_cc_op() before calling the
        helper to be sure env->cc_op and s->cc_op
        are synchronized
    v6: use helpers as suggested by Richard

 linux-user/main.c       |  7 +++++
 target/m68k/cpu.c       |  2 ++
 target/m68k/cpu.h       |  1 +
 target/m68k/helper.h    |  3 ++
 target/m68k/op_helper.c | 61 +++++++++++++++++++++++++++++++++++++++
 target/m68k/translate.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++++-
 6 files changed, 150 insertions(+), 1 deletion(-)

Comments

Richard Henderson Jan. 4, 2018, 7:10 a.m. UTC | #1
On 01/03/2018 05:29 PM, Laurent Vivier wrote:
> +    /* From the specs:
> +     *   X: Not affected, N,V: Undefined,
> +     *   Z: Set if val is equal to lb or ub
> +     *   V: Set if val < lb or val > ub, cleared otherwise
            ^^
Just a typo here.

Otherwise,

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>


r~
diff mbox

Patch

diff --git a/linux-user/main.c b/linux-user/main.c
index 71696ed33d..99a551b04f 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -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;
diff --git a/target/m68k/cpu.c b/target/m68k/cpu.c
index 0a3dd83548..57ffcb2114 100644
--- a/target/m68k/cpu.c
+++ b/target/m68k/cpu.c
@@ -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)
diff --git a/target/m68k/cpu.h b/target/m68k/cpu.h
index cd4b3a7c7b..68396bdd70 100644
--- a/target/m68k/cpu.h
+++ b/target/m68k/cpu.h
@@ -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)
diff --git a/target/m68k/helper.h b/target/m68k/helper.h
index eebe52dae5..78483da003 100644
--- a/target/m68k/helper.h
+++ b/target/m68k/helper.h
@@ -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)
diff --git a/target/m68k/op_helper.c b/target/m68k/op_helper.c
index 5c7b27b9ca..06144d436d 100644
--- a/target/m68k/op_helper.c
+++ b/target/m68k/op_helper.c
@@ -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
+     *   V: 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);
+    }
+}
diff --git a/target/m68k/translate.c b/target/m68k/translate.c
index a1e424e3db..7f52065375 100644
--- a/target/m68k/translate.c
+++ b/target/m68k/translate.c
@@ -4203,6 +4203,80 @@  DISAS_INSN(ff1)
     gen_helper_ff1(reg, reg);
 }
 
+DISAS_INSN(chk)
+{
+    TCGv src, reg;
+    int opsize;
+
+    switch ((insn >> 7) & 3) {
+    case 3:
+        opsize = OS_WORD;
+        break;
+    case 2:
+        if (m68k_feature(env, M68K_FEATURE_CHK2)) {
+            opsize = OS_LONG;
+            break;
+        }
+        /* fallthru */
+    default:
+        gen_exception(s, s->insn_pc, EXCP_ILLEGAL);
+        return;
+    }
+    SRC_EA(env, src, opsize, 1, NULL);
+    reg = gen_extend(DREG(insn, 9), opsize, 1);
+
+    gen_flush_flags(s);
+    gen_helper_chk(cpu_env, reg, src);
+}
+
+DISAS_INSN(chk2)
+{
+    uint16_t ext;
+    TCGv addr1, addr2, bound1, bound2, reg;
+    int opsize;
+
+    switch ((insn >> 9) & 3) {
+    case 0:
+        opsize = OS_BYTE;
+        break;
+    case 1:
+        opsize = OS_WORD;
+        break;
+    case 2:
+        opsize = OS_LONG;
+        break;
+    default:
+        gen_exception(s, s->insn_pc, EXCP_ILLEGAL);
+        return;
+    }
+
+    ext = read_im16(env, s);
+    if ((ext & 0x0800) == 0) {
+        gen_exception(s, s->insn_pc, EXCP_ILLEGAL);
+        return;
+    }
+
+    addr1 = gen_lea(env, s, insn, OS_UNSIZED);
+    addr2 = tcg_temp_new();
+    tcg_gen_addi_i32(addr2, addr1, opsize_bytes(opsize));
+
+    bound1 = gen_load(s, opsize, addr1, 1);
+    tcg_temp_free(addr1);
+    bound2 = gen_load(s, opsize, addr2, 1);
+    tcg_temp_free(addr2);
+
+    reg = tcg_temp_new();
+    if (ext & 0x8000) {
+        tcg_gen_mov_i32(reg, AREG(ext, 12));
+    } else {
+        gen_ext(reg, DREG(ext, 12), opsize, 1);
+    }
+
+    gen_flush_flags(s);
+    gen_helper_chk2(cpu_env, reg, bound1, bound2);
+    tcg_temp_free(reg);
+}
+
 static TCGv gen_get_sr(DisasContext *s)
 {
     TCGv ccr;
@@ -5306,7 +5380,7 @@  void register_m68k_insns (CPUM68KState *env)
     BASE(undef,     0000, 0000);
     INSN(arith_im,  0080, fff8, CF_ISA_A);
     INSN(arith_im,  0000, ff00, M68000);
-    INSN(undef,     00c0, ffc0, M68000);
+    INSN(chk2,      00c0, f9c0, CHK2);
     INSN(bitrev,    00c0, fff8, CF_ISA_APLUSC);
     BASE(bitop_reg, 0100, f1c0);
     BASE(bitop_reg, 0140, f1c0);
@@ -5339,6 +5413,7 @@  void register_m68k_insns (CPUM68KState *env)
     BASE(move,      1000, f000);
     BASE(move,      2000, f000);
     BASE(move,      3000, f000);
+    INSN(chk,       4000, f040, M68000);
     INSN(strldsr,   40e7, ffff, CF_ISA_APLUSC);
     INSN(negx,      4080, fff8, CF_ISA_A);
     INSN(negx,      4000, ff00, M68000);