mirror of
https://github.com/qemu/qemu.git
synced 2024-11-26 12:23:36 +08:00
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: Laurent Vivier <laurent@vivier.eu> Suggested-by: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-Id: <20180104012913.30763-8-laurent@vivier.eu>
This commit is contained in:
parent
d2f8fb8e7f
commit
8bf6cbaf39
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user