target-s390: Send signals for divide

Signed-off-by: Richard Henderson <rth@twiddle.net>
This commit is contained in:
Richard Henderson 2012-09-05 17:27:40 -07:00
parent 891452e5e2
commit b4e2bd3563
3 changed files with 67 additions and 6 deletions

View File

@ -931,5 +931,7 @@ uint32_t set_cc_nz_f64(float64 v);
/* misc_helper.c */
void program_interrupt(CPUS390XState *env, uint32_t code, int ilen);
void QEMU_NORETURN runtime_exception(CPUS390XState *env, int excp,
uintptr_t retaddr);
#endif

View File

@ -38,22 +38,54 @@ uint64_t HELPER(mul128)(CPUS390XState *env, uint64_t v1, uint64_t v2)
}
/* 64/32 -> 32 signed division */
int64_t HELPER(divs32)(CPUS390XState *env, int64_t a, int64_t b)
int64_t HELPER(divs32)(CPUS390XState *env, int64_t a, int64_t b64)
{
env->retxl = a % (int32_t)b;
return a / (int32_t)b;
int32_t ret, b = b64;
int64_t q;
if (b == 0) {
runtime_exception(env, PGM_FIXPT_DIVIDE, GETPC());
}
ret = q = a / b;
env->retxl = a % b;
/* Catch non-representable quotient. */
if (ret != q) {
runtime_exception(env, PGM_FIXPT_DIVIDE, GETPC());
}
return ret;
}
/* 64/32 -> 32 unsigned division */
uint64_t HELPER(divu32)(CPUS390XState *env, uint64_t a, uint64_t b)
uint64_t HELPER(divu32)(CPUS390XState *env, uint64_t a, uint64_t b64)
{
env->retxl = a % (uint32_t)b;
return a / (uint32_t)b;
uint32_t ret, b = b64;
uint64_t q;
if (b == 0) {
runtime_exception(env, PGM_FIXPT_DIVIDE, GETPC());
}
ret = q = a / b;
env->retxl = a % b;
/* Catch non-representable quotient. */
if (ret != q) {
runtime_exception(env, PGM_FIXPT_DIVIDE, GETPC());
}
return ret;
}
/* 64/64 -> 64 signed division */
int64_t HELPER(divs64)(CPUS390XState *env, int64_t a, int64_t b)
{
/* Catch divide by zero, and non-representable quotient (MIN / -1). */
if (b == 0 || (b == -1 && a == (1ll << 63))) {
runtime_exception(env, PGM_FIXPT_DIVIDE, GETPC());
}
env->retxl = a % b;
return a / b;
}
@ -63,6 +95,10 @@ uint64_t HELPER(divu64)(CPUS390XState *env, uint64_t ah, uint64_t al,
uint64_t b)
{
uint64_t ret;
/* Signal divide by zero. */
if (b == 0) {
runtime_exception(env, PGM_FIXPT_DIVIDE, GETPC());
}
if (ah == 0) {
/* 64 -> 64/64 case */
env->retxl = al % b;
@ -75,6 +111,9 @@ uint64_t HELPER(divu64)(CPUS390XState *env, uint64_t ah, uint64_t al,
__uint128_t q = a / b;
env->retxl = a % b;
ret = q;
if (ret != q) {
runtime_exception(env, PGM_FIXPT_DIVIDE, GETPC());
}
#else
/* 32-bit hosts would need special wrapper functionality - just abort if
we encounter such a case; it's very unlikely anyways. */

View File

@ -41,6 +41,26 @@
#define HELPER_LOG(x...)
#endif
/* Raise an exception dynamically from a helper function. */
void QEMU_NORETURN runtime_exception(CPUS390XState *env, int excp,
uintptr_t retaddr)
{
int t;
env->exception_index = EXCP_PGM;
env->int_pgm_code = excp;
/* Use the (ultimate) callers address to find the insn that trapped. */
cpu_restore_state(env, retaddr);
/* Advance past the insn. */
t = cpu_ldub_code(env, env->psw.addr);
env->int_pgm_ilen = t = get_ilen(t);
env->psw.addr += 2 * t;
cpu_loop_exit(env);
}
/* Raise an exception statically from a TB. */
void HELPER(exception)(CPUS390XState *env, uint32_t excp)
{