mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-03 07:43:54 -06:00
target-sparc: Introduce cpu_raise_exception_ra
Several helpers call helper_raise_exception directly, which requires in turn that their callers have performed save_state. The new function allows a TCG return address to be passed in so that we can restore PC + NPC + flags data from that. This fixes a bug in the usage of helper_check_align, whose callers had not been calling save_state. It fixes another bug in which the divide helpers used GETPC at a level other than the direct callee from TCG. This allows the translator to avoid save_state prior to SAVE, RESTORE, and FLUSHW instructions. Tested-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk> Signed-off-by: Richard Henderson <rth@twiddle.net>
This commit is contained in:
parent
808832277a
commit
2f9d35fc40
5 changed files with 82 additions and 96 deletions
|
@ -24,6 +24,14 @@
|
|||
#include "exec/helper-proto.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
|
||||
void cpu_raise_exception_ra(CPUSPARCState *env, int tt, uintptr_t ra)
|
||||
{
|
||||
CPUState *cs = CPU(sparc_env_get_cpu(env));
|
||||
|
||||
cs->exception_index = tt;
|
||||
cpu_loop_exit_restore(cs, ra);
|
||||
}
|
||||
|
||||
void helper_raise_exception(CPUSPARCState *env, int tt)
|
||||
{
|
||||
CPUState *cs = CPU(sparc_env_get_cpu(env));
|
||||
|
@ -59,7 +67,7 @@ uint64_t helper_tick_get_count(CPUSPARCState *env, void *opaque, int mem_idx)
|
|||
CPUTimer *timer = opaque;
|
||||
|
||||
if (timer->npt && mem_idx < MMU_KERNEL_IDX) {
|
||||
helper_raise_exception(env, TT_PRIV_INSN);
|
||||
cpu_raise_exception_ra(env, TT_PRIV_INSN, GETPC());
|
||||
}
|
||||
|
||||
return cpu_tick_get_count(timer);
|
||||
|
@ -76,10 +84,9 @@ void helper_tick_set_limit(void *opaque, uint64_t limit)
|
|||
}
|
||||
#endif
|
||||
|
||||
static target_ulong helper_udiv_common(CPUSPARCState *env, target_ulong a,
|
||||
target_ulong b, int cc)
|
||||
static target_ulong do_udiv(CPUSPARCState *env, target_ulong a,
|
||||
target_ulong b, int cc, uintptr_t ra)
|
||||
{
|
||||
SPARCCPU *cpu = sparc_env_get_cpu(env);
|
||||
int overflow = 0;
|
||||
uint64_t x0;
|
||||
uint32_t x1;
|
||||
|
@ -88,8 +95,7 @@ static target_ulong helper_udiv_common(CPUSPARCState *env, target_ulong a,
|
|||
x1 = (b & 0xffffffff);
|
||||
|
||||
if (x1 == 0) {
|
||||
cpu_restore_state(CPU(cpu), GETPC());
|
||||
helper_raise_exception(env, TT_DIV_ZERO);
|
||||
cpu_raise_exception_ra(env, TT_DIV_ZERO, ra);
|
||||
}
|
||||
|
||||
x0 = x0 / x1;
|
||||
|
@ -108,18 +114,17 @@ static target_ulong helper_udiv_common(CPUSPARCState *env, target_ulong a,
|
|||
|
||||
target_ulong helper_udiv(CPUSPARCState *env, target_ulong a, target_ulong b)
|
||||
{
|
||||
return helper_udiv_common(env, a, b, 0);
|
||||
return do_udiv(env, a, b, 0, GETPC());
|
||||
}
|
||||
|
||||
target_ulong helper_udiv_cc(CPUSPARCState *env, target_ulong a, target_ulong b)
|
||||
{
|
||||
return helper_udiv_common(env, a, b, 1);
|
||||
return do_udiv(env, a, b, 1, GETPC());
|
||||
}
|
||||
|
||||
static target_ulong helper_sdiv_common(CPUSPARCState *env, target_ulong a,
|
||||
target_ulong b, int cc)
|
||||
static target_ulong do_sdiv(CPUSPARCState *env, target_ulong a,
|
||||
target_ulong b, int cc, uintptr_t ra)
|
||||
{
|
||||
SPARCCPU *cpu = sparc_env_get_cpu(env);
|
||||
int overflow = 0;
|
||||
int64_t x0;
|
||||
int32_t x1;
|
||||
|
@ -128,8 +133,7 @@ static target_ulong helper_sdiv_common(CPUSPARCState *env, target_ulong a,
|
|||
x1 = (b & 0xffffffff);
|
||||
|
||||
if (x1 == 0) {
|
||||
cpu_restore_state(CPU(cpu), GETPC());
|
||||
helper_raise_exception(env, TT_DIV_ZERO);
|
||||
cpu_raise_exception_ra(env, TT_DIV_ZERO, ra);
|
||||
} else if (x1 == -1 && x0 == INT64_MIN) {
|
||||
x0 = INT32_MAX;
|
||||
overflow = 1;
|
||||
|
@ -151,12 +155,12 @@ static target_ulong helper_sdiv_common(CPUSPARCState *env, target_ulong a,
|
|||
|
||||
target_ulong helper_sdiv(CPUSPARCState *env, target_ulong a, target_ulong b)
|
||||
{
|
||||
return helper_sdiv_common(env, a, b, 0);
|
||||
return do_sdiv(env, a, b, 0, GETPC());
|
||||
}
|
||||
|
||||
target_ulong helper_sdiv_cc(CPUSPARCState *env, target_ulong a, target_ulong b)
|
||||
{
|
||||
return helper_sdiv_common(env, a, b, 1);
|
||||
return do_sdiv(env, a, b, 1, GETPC());
|
||||
}
|
||||
|
||||
#ifdef TARGET_SPARC64
|
||||
|
@ -164,10 +168,7 @@ int64_t helper_sdivx(CPUSPARCState *env, int64_t a, int64_t b)
|
|||
{
|
||||
if (b == 0) {
|
||||
/* Raise divide by zero trap. */
|
||||
SPARCCPU *cpu = sparc_env_get_cpu(env);
|
||||
|
||||
cpu_restore_state(CPU(cpu), GETPC());
|
||||
helper_raise_exception(env, TT_DIV_ZERO);
|
||||
cpu_raise_exception_ra(env, TT_DIV_ZERO, GETPC());
|
||||
} else if (b == -1) {
|
||||
/* Avoid overflow trap with i386 divide insn. */
|
||||
return -a;
|
||||
|
@ -180,10 +181,7 @@ uint64_t helper_udivx(CPUSPARCState *env, uint64_t a, uint64_t b)
|
|||
{
|
||||
if (b == 0) {
|
||||
/* Raise divide by zero trap. */
|
||||
SPARCCPU *cpu = sparc_env_get_cpu(env);
|
||||
|
||||
cpu_restore_state(CPU(cpu), GETPC());
|
||||
helper_raise_exception(env, TT_DIV_ZERO);
|
||||
cpu_raise_exception_ra(env, TT_DIV_ZERO, GETPC());
|
||||
}
|
||||
return a / b;
|
||||
}
|
||||
|
@ -192,7 +190,6 @@ uint64_t helper_udivx(CPUSPARCState *env, uint64_t a, uint64_t b)
|
|||
target_ulong helper_taddcctv(CPUSPARCState *env, target_ulong src1,
|
||||
target_ulong src2)
|
||||
{
|
||||
SPARCCPU *cpu = sparc_env_get_cpu(env);
|
||||
target_ulong dst;
|
||||
|
||||
/* Tag overflow occurs if either input has bits 0 or 1 set. */
|
||||
|
@ -215,14 +212,12 @@ target_ulong helper_taddcctv(CPUSPARCState *env, target_ulong src1,
|
|||
return dst;
|
||||
|
||||
tag_overflow:
|
||||
cpu_restore_state(CPU(cpu), GETPC());
|
||||
helper_raise_exception(env, TT_TOVF);
|
||||
cpu_raise_exception_ra(env, TT_TOVF, GETPC());
|
||||
}
|
||||
|
||||
target_ulong helper_tsubcctv(CPUSPARCState *env, target_ulong src1,
|
||||
target_ulong src2)
|
||||
{
|
||||
SPARCCPU *cpu = sparc_env_get_cpu(env);
|
||||
target_ulong dst;
|
||||
|
||||
/* Tag overflow occurs if either input has bits 0 or 1 set. */
|
||||
|
@ -245,8 +240,7 @@ target_ulong helper_tsubcctv(CPUSPARCState *env, target_ulong src1,
|
|||
return dst;
|
||||
|
||||
tag_overflow:
|
||||
cpu_restore_state(CPU(cpu), GETPC());
|
||||
helper_raise_exception(env, TT_TOVF);
|
||||
cpu_raise_exception_ra(env, TT_TOVF, GETPC());
|
||||
}
|
||||
|
||||
#ifndef TARGET_SPARC64
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue