target-m68k: add 680x0 divu/divs variants

Update helper to set the throwing location in case of div-by-0.
Cleanup divX.w and add quad word variants of divX.l.

Signed-off-by: Laurent Vivier <laurent@vivier.eu>
Reviewed-by: Richard Henderson <rth@twidle.net>
[laurent: modified to clear Z on overflow, as found with risu]
This commit is contained in:
Laurent Vivier 2016-10-28 20:42:23 +02:00
parent 8be95defd6
commit 0ccb9c1d81
6 changed files with 221 additions and 73 deletions

View file

@ -1242,64 +1242,74 @@ DISAS_INSN(mulw)
DISAS_INSN(divw)
{
TCGv reg;
TCGv tmp;
TCGv src;
int sign;
TCGv src;
TCGv destr;
/* divX.w <EA>,Dn 32/16 -> 16r:16q */
sign = (insn & 0x100) != 0;
reg = DREG(insn, 9);
if (sign) {
tcg_gen_ext16s_i32(QREG_DIV1, reg);
} else {
tcg_gen_ext16u_i32(QREG_DIV1, reg);
}
SRC_EA(env, src, OS_WORD, sign, NULL);
tcg_gen_mov_i32(QREG_DIV2, src);
if (sign) {
gen_helper_divs(cpu_env, tcg_const_i32(1));
} else {
gen_helper_divu(cpu_env, tcg_const_i32(1));
}
tmp = tcg_temp_new();
src = tcg_temp_new();
tcg_gen_ext16u_i32(tmp, QREG_DIV1);
tcg_gen_shli_i32(src, QREG_DIV2, 16);
tcg_gen_or_i32(reg, tmp, src);
/* dest.l / src.w */
SRC_EA(env, src, OS_WORD, sign, NULL);
destr = tcg_const_i32(REG(insn, 9));
if (sign) {
gen_helper_divsw(cpu_env, destr, src);
} else {
gen_helper_divuw(cpu_env, destr, src);
}
tcg_temp_free(destr);
set_cc_op(s, CC_OP_FLAGS);
}
DISAS_INSN(divl)
{
TCGv num;
TCGv den;
TCGv reg;
TCGv num, reg, den;
int sign;
uint16_t ext;
ext = read_im16(env, s);
if (ext & 0x87f8) {
gen_exception(s, s->pc - 4, EXCP_UNSUPPORTED);
sign = (ext & 0x0800) != 0;
if (ext & 0x400) {
if (!m68k_feature(s->env, M68K_FEATURE_QUAD_MULDIV)) {
gen_exception(s, s->insn_pc, EXCP_ILLEGAL);
return;
}
/* divX.l <EA>, Dr:Dq 64/32 -> 32r:32q */
SRC_EA(env, den, OS_LONG, 0, NULL);
num = tcg_const_i32(REG(ext, 12));
reg = tcg_const_i32(REG(ext, 0));
if (sign) {
gen_helper_divsll(cpu_env, num, reg, den);
} else {
gen_helper_divull(cpu_env, num, reg, den);
}
tcg_temp_free(reg);
tcg_temp_free(num);
set_cc_op(s, CC_OP_FLAGS);
return;
}
num = DREG(ext, 12);
reg = DREG(ext, 0);
tcg_gen_mov_i32(QREG_DIV1, num);
/* divX.l <EA>, Dq 32/32 -> 32q */
/* divXl.l <EA>, Dr:Dq 32/32 -> 32r:32q */
SRC_EA(env, den, OS_LONG, 0, NULL);
tcg_gen_mov_i32(QREG_DIV2, den);
if (ext & 0x0800) {
gen_helper_divs(cpu_env, tcg_const_i32(0));
num = tcg_const_i32(REG(ext, 12));
reg = tcg_const_i32(REG(ext, 0));
if (sign) {
gen_helper_divsl(cpu_env, num, reg, den);
} else {
gen_helper_divu(cpu_env, tcg_const_i32(0));
}
if ((ext & 7) == ((ext >> 12) & 7)) {
/* div */
tcg_gen_mov_i32 (reg, QREG_DIV1);
} else {
/* rem */
tcg_gen_mov_i32 (reg, QREG_DIV2);
gen_helper_divul(cpu_env, num, reg, den);
}
tcg_temp_free(reg);
tcg_temp_free(num);
set_cc_op(s, CC_OP_FLAGS);
}