#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));
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);
}
#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;
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;
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;
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;
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
{
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;
{
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;
}
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. */
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. */
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
}
#endif
-void helper_check_align(CPUSPARCState *env, target_ulong addr, uint32_t align)
+static void do_check_align(CPUSPARCState *env, target_ulong addr,
+ uint32_t align, uintptr_t ra)
{
if (addr & align) {
#ifdef DEBUG_UNALIGNED
printf("Unaligned access to 0x" TARGET_FMT_lx " from 0x" TARGET_FMT_lx
"\n", addr, env->pc);
#endif
- helper_raise_exception(env, TT_UNALIGNED);
+ cpu_raise_exception_ra(env, TT_UNALIGNED, ra);
}
}
+void helper_check_align(CPUSPARCState *env, target_ulong addr, uint32_t align)
+{
+ do_check_align(env, addr, align, GETPC());
+}
+
#if !defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY) && \
defined(DEBUG_MXCC)
static void dump_mxcc(CPUSPARCState *env)
uint32_t last_addr = addr;
#endif
- helper_check_align(env, addr, size - 1);
+ do_check_align(env, addr, size - 1, GETPC());
switch (asi) {
case ASI_M_MXCC: /* SuperSparc MXCC registers, or... */
/* case ASI_LEON_CACHEREGS: Leon3 cache control */
SPARCCPU *cpu = sparc_env_get_cpu(env);
CPUState *cs = CPU(cpu);
- helper_check_align(env, addr, size - 1);
+ do_check_align(env, addr, size - 1, GETPC());
switch (asi) {
case ASI_M_MXCC: /* SuperSparc MXCC registers, or... */
/* case ASI_LEON_CACHEREGS: Leon3 cache control */
#endif
if (asi < 0x80) {
- helper_raise_exception(env, TT_PRIV_ACT);
+ cpu_raise_exception_ra(env, TT_PRIV_ACT, GETPC());
}
- helper_check_align(env, addr, size - 1);
+ do_check_align(env, addr, size - 1, GETPC());
addr = asi_address_mask(env, asi, addr);
switch (asi) {
dump_asi("write", addr, asi, size, val);
#endif
if (asi < 0x80) {
- helper_raise_exception(env, TT_PRIV_ACT);
+ cpu_raise_exception_ra(env, TT_PRIV_ACT, GETPC());
}
-
- helper_check_align(env, addr, size - 1);
+ do_check_align(env, addr, size - 1, GETPC());
addr = asi_address_mask(env, asi, addr);
/* Convert to little endian */
case ASI_PNFL: /* Primary no-fault LE, RO */
case ASI_SNFL: /* Secondary no-fault LE, RO */
default:
- helper_raise_exception(env, TT_DATA_ACCESS);
+ cpu_raise_exception_ra(env, TT_DATA_ACCESS, GETPC());
return;
}
}
|| (cpu_has_hypervisor(env)
&& asi >= 0x30 && asi < 0x80
&& !(env->hpstate & HS_PRIV))) {
- helper_raise_exception(env, TT_PRIV_ACT);
+ cpu_raise_exception_ra(env, TT_PRIV_ACT, GETPC());
}
- helper_check_align(env, addr, size - 1);
+ do_check_align(env, addr, size - 1, GETPC());
addr = asi_address_mask(env, asi, addr);
/* process nonfaulting loads first */
dump_asi("read ", last_addr, asi, size, ret);
#endif
/* env->exception_index is set in get_physical_address_data(). */
- helper_raise_exception(env, cs->exception_index);
+ cpu_raise_exception_ra(env, cs->exception_index, GETPC());
}
/* convert nonfaulting load ASIs to normal load ASIs */
case ASI_TWINX_S: /* Secondary, twinx */
case ASI_TWINX_SL: /* Secondary, twinx, LE */
/* These are all 128-bit atomic; only ldda (now ldtxa) allowed */
- helper_raise_exception(env, TT_ILL_INSN);
+ cpu_raise_exception_ra(env, TT_ILL_INSN, GETPC());
return 0;
}
|| (cpu_has_hypervisor(env)
&& asi >= 0x30 && asi < 0x80
&& !(env->hpstate & HS_PRIV))) {
- helper_raise_exception(env, TT_PRIV_ACT);
+ cpu_raise_exception_ra(env, TT_PRIV_ACT, GETPC());
}
- helper_check_align(env, addr, size - 1);
+ do_check_align(env, addr, size - 1, GETPC());
addr = asi_address_mask(env, asi, addr);
/* Convert to little endian */
case ASI_TWINX_S: /* Secondary, twinx */
case ASI_TWINX_SL: /* Secondary, twinx, LE */
/* Only stda allowed */
- helper_raise_exception(env, TT_ILL_INSN);
+ cpu_raise_exception_ra(env, TT_ILL_INSN, GETPC());
return;
case ASI_DCACHE_DATA: /* D-cache data */
case ASI_DCACHE_TAG: /* D-cache tag access */
|| (cpu_has_hypervisor(env)
&& asi >= 0x30 && asi < 0x80
&& !(env->hpstate & HS_PRIV))) {
- helper_raise_exception(env, TT_PRIV_ACT);
+ cpu_raise_exception_ra(env, TT_PRIV_ACT, GETPC());
}
addr = asi_address_mask(env, asi, addr);
#if !defined(CONFIG_USER_ONLY)
case ASI_TWINX_AIUP: /* As if user primary, twinx */
case ASI_TWINX_AIUP_L: /* As if user primary, twinx, LE */
- helper_check_align(env, addr, 0xf);
+ do_check_align(env, addr, 0xf, GETPC());
h = cpu_ldq_user(env, addr);
l = cpu_ldq_user(env, addr + 8);
break;
case ASI_TWINX_AIUS: /* As if user secondary, twinx */
case ASI_TWINX_AIUS_L: /* As if user secondary, twinx, LE */
- helper_check_align(env, addr, 0xf);
+ do_check_align(env, addr, 0xf, GETPC());
h = cpu_ldq_user_secondary(env, addr);
l = cpu_ldq_user_secondary(env, addr + 8);
break;
case ASI_TWINX_REAL: /* Real address, twinx */
case ASI_TWINX_REAL_L: /* Real address, twinx, LE */
- helper_check_align(env, addr, 0xf);
+ do_check_align(env, addr, 0xf, GETPC());
{
CPUState *cs = CPU(sparc_env_get_cpu(env));
h = ldq_phys(cs->as, addr);
case ASI_NUCLEUS_QUAD_LDD_L:
case ASI_TWINX_N: /* Nucleus, twinx */
case ASI_TWINX_NL: /* Nucleus, twinx, LE */
- helper_check_align(env, addr, 0xf);
+ do_check_align(env, addr, 0xf, GETPC());
h = cpu_ldq_nucleus(env, addr);
l = cpu_ldq_nucleus(env, addr + 8);
break;
case ASI_TWINX_S: /* Secondary, twinx */
case ASI_TWINX_SL: /* Secondary, twinx, LE */
if (!cpu_hypervisor_mode(env)) {
- helper_check_align(env, addr, 0xf);
+ do_check_align(env, addr, 0xf, GETPC());
if (env->pstate & PS_PRIV) {
h = cpu_ldq_kernel_secondary(env, addr);
l = cpu_ldq_kernel_secondary(env, addr + 8);
/* fallthru */
case ASI_TWINX_P: /* Primary, twinx */
case ASI_TWINX_PL: /* Primary, twinx, LE */
- helper_check_align(env, addr, 0xf);
+ do_check_align(env, addr, 0xf, GETPC());
h = cpu_ldq_data(env, addr);
l = cpu_ldq_data(env, addr + 8);
break;
case ASI_TWINX_SL: /* Primary, twinx, LE */
/* ??? Should be available, but we need to implement
an atomic 128-bit load. */
- helper_raise_exception(env, TT_PRIV_ACT);
+ cpu_raise_exception_ra(env, TT_PRIV_ACT, GETPC());
#endif
default:
/* Non-twinx asi, so this is the legacy ldda insn, which
/* ??? The UA2011 manual recommends emulating this with
a single 64-bit load. However, LE asis *are* treated
as two 32-bit loads individually byte swapped. */
- helper_check_align(env, addr, 0x7);
+ do_check_align(env, addr, 7, GETPC());
QT0.high = (uint32_t)helper_ld_asi(env, addr, asi, MO_UL);
QT0.low = (uint32_t)helper_ld_asi(env, addr + 4, asi, MO_UL);
return;
/* XXX add 128 bit load */
CPU_QuadU u;
- helper_check_align(env, addr, 7);
+ do_check_align(env, addr, 7, GETPC());
#if !defined(CONFIG_USER_ONLY)
switch (mem_idx) {
case MMU_USER_IDX:
/* XXX add 128 bit store */
CPU_QuadU u;
- helper_check_align(env, addr, 7);
+ do_check_align(env, addr, 7, GETPC());
#if !defined(CONFIG_USER_ONLY)
switch (mem_idx) {
case MMU_USER_IDX:
}
if ((env->mmuregs[0] & MMU_E) && !(env->mmuregs[0] & MMU_NF)) {
- if (is_exec) {
- helper_raise_exception(env, TT_CODE_ACCESS);
- } else {
- helper_raise_exception(env, TT_DATA_ACCESS);
- }
+ int tt = is_exec ? TT_CODE_ACCESS : TT_DATA_ACCESS;
+ cpu_raise_exception_ra(env, tt, GETPC());
}
/* flush neverland mappings created during no-fault mode,
{
SPARCCPU *cpu = SPARC_CPU(cs);
CPUSPARCState *env = &cpu->env;
+ int tt = is_exec ? TT_CODE_ACCESS : TT_DATA_ACCESS;
#ifdef DEBUG_UNASSIGNED
printf("Unassigned mem access to " TARGET_FMT_plx " from " TARGET_FMT_lx
"\n", addr, env->pc);
#endif
- if (is_exec) {
- helper_raise_exception(env, TT_CODE_ACCESS);
- } else {
- helper_raise_exception(env, TT_DATA_ACCESS);
- }
+ cpu_raise_exception_ra(env, tt, GETPC());
}
#endif
#endif
printf("Unaligned access to 0x" TARGET_FMT_lx " from 0x" TARGET_FMT_lx
"\n", addr, env->pc);
#endif
- if (retaddr) {
- cpu_restore_state(CPU(cpu), retaddr);
- }
- helper_raise_exception(env, TT_UNALIGNED);
+ cpu_raise_exception_ra(env, TT_UNALIGNED, retaddr);
}
/* try to fill the TLB and return an exception if error. If retaddr is
ret = sparc_cpu_handle_mmu_fault(cs, addr, access_type, mmu_idx);
if (ret) {
- if (retaddr) {
- cpu_restore_state(cs, retaddr);
- }
- cpu_loop_exit(cs);
+ cpu_loop_exit_restore(cs, retaddr);
}
}
#endif
#include "qemu/osdep.h"
#include "cpu.h"
+#include "exec/exec-all.h"
#include "exec/helper-proto.h"
#include "trace.h"
unsigned int cwp;
if (env->psret == 1) {
- helper_raise_exception(env, TT_ILL_INSN);
+ cpu_raise_exception_ra(env, TT_ILL_INSN, GETPC());
}
env->psret = 1;
cwp = cpu_cwp_inc(env, env->cwp + 1) ;
if (env->wim & (1 << cwp)) {
- helper_raise_exception(env, TT_WIN_UNF);
+ cpu_raise_exception_ra(env, TT_WIN_UNF, GETPC());
}
cpu_set_cwp(env, cwp);
env->psrs = env->psrps;
cwp = cpu_cwp_dec(env, env->cwp - 1);
if (env->wim & (1 << cwp)) {
- helper_raise_exception(env, TT_WIN_OVF);
+ cpu_raise_exception_ra(env, TT_WIN_OVF, GETPC());
}
cpu_set_cwp(env, cwp);
}
cwp = cpu_cwp_inc(env, env->cwp + 1);
if (env->wim & (1 << cwp)) {
- helper_raise_exception(env, TT_WIN_UNF);
+ cpu_raise_exception_ra(env, TT_WIN_UNF, GETPC());
}
cpu_set_cwp(env, cwp);
}
void helper_wrpsr(CPUSPARCState *env, target_ulong new_psr)
{
if ((new_psr & PSR_CWP) >= env->nwindows) {
- helper_raise_exception(env, TT_ILL_INSN);
+ cpu_raise_exception_ra(env, TT_ILL_INSN, GETPC());
} else {
cpu_put_psr(env, new_psr);
}
cwp = cpu_cwp_dec(env, env->cwp - 1);
if (env->cansave == 0) {
- helper_raise_exception(env, TT_SPILL | (env->otherwin != 0 ?
- (TT_WOTHER |
- ((env->wstate & 0x38) >> 1)) :
- ((env->wstate & 0x7) << 2)));
+ int tt = TT_SPILL | (env->otherwin != 0
+ ? (TT_WOTHER | ((env->wstate & 0x38) >> 1))
+ : ((env->wstate & 0x7) << 2));
+ cpu_raise_exception_ra(env, tt, GETPC());
} else {
if (env->cleanwin - env->canrestore == 0) {
/* XXX Clean windows without trap */
- helper_raise_exception(env, TT_CLRWIN);
+ cpu_raise_exception_ra(env, TT_CLRWIN, GETPC());
} else {
env->cansave--;
env->canrestore++;
cwp = cpu_cwp_inc(env, env->cwp + 1);
if (env->canrestore == 0) {
- helper_raise_exception(env, TT_FILL | (env->otherwin != 0 ?
- (TT_WOTHER |
- ((env->wstate & 0x38) >> 1)) :
- ((env->wstate & 0x7) << 2)));
+ int tt = TT_FILL | (env->otherwin != 0
+ ? (TT_WOTHER | ((env->wstate & 0x38) >> 1))
+ : ((env->wstate & 0x7) << 2));
+ cpu_raise_exception_ra(env, tt, GETPC());
} else {
env->cansave++;
env->canrestore--;
void helper_flushw(CPUSPARCState *env)
{
if (env->cansave != env->nwindows - 2) {
- helper_raise_exception(env, TT_SPILL | (env->otherwin != 0 ?
- (TT_WOTHER |
- ((env->wstate & 0x38) >> 1)) :
- ((env->wstate & 0x7) << 2)));
+ int tt = TT_SPILL | (env->otherwin != 0
+ ? (TT_WOTHER | ((env->wstate & 0x38) >> 1))
+ : ((env->wstate & 0x7) << 2));
+ cpu_raise_exception_ra(env, tt, GETPC());
}
}