#include "softmmu_exec.h"
#endif /* !defined(CONFIG_USER_ONLY) */
-//#define DEBUG_PCALL
//#define DEBUG_MMU
//#define DEBUG_MXCC
//#define DEBUG_UNALIGNED
#define DPRINTF_ASI(fmt, args...) do {} while (0)
#endif
-#ifdef TARGET_ABI32
-#define ABI32_MASK(addr) do { (addr) &= 0xffffffffULL; } while (0)
+#ifdef TARGET_SPARC64
+#ifndef TARGET_ABI32
+#define AM_CHECK(env1) ((env1)->pstate & PS_AM)
#else
-#define ABI32_MASK(addr) do {} while (0)
+#define AM_CHECK(env1) (1)
+#endif
+#endif
+
+static inline void address_mask(CPUState *env1, target_ulong *addr)
+{
+#ifdef TARGET_SPARC64
+ if (AM_CHECK(env1))
+ *addr &= 0xffffffffULL;
#endif
+}
void raise_exception(int tt)
{
}
}
+static inline void set_cwp(int new_cwp)
+{
+ cpu_set_cwp(env, new_cwp);
+}
+
void helper_check_align(target_ulong addr, uint32_t align)
{
if (addr & align) {
uint64_t tmp;
tmp = (*((uint64_t *)&DT0)) << ((env->gsr & 7) * 8);
- tmp |= (*((uint64_t *)&DT1)) >> (64 - (env->gsr & 7) * 8);
+ /* on many architectures a shift of 64 does nothing */
+ if ((env->gsr & 7) != 0) {
+ tmp |= (*((uint64_t *)&DT1)) >> (64 - (env->gsr & 7) * 8);
+ }
*((uint64_t *)&DT0) = tmp;
}
(val & 0x00ffffff);
// Mappings generated during no-fault mode or MMU
// disabled mode are invalid in normal mode
- if ((oldreg & (MMU_E | MMU_NF | env->mmu_bm)) !=
- (env->mmuregs[reg] & (MMU_E | MMU_NF | env->mmu_bm)))
+ if ((oldreg & (MMU_E | MMU_NF | env->def->mmu_bm)) !=
+ (env->mmuregs[reg] & (MMU_E | MMU_NF | env->def->mmu_bm)))
tlb_flush(env, 1);
break;
case 1: // Context Table Pointer Register
- env->mmuregs[reg] = val & env->mmu_ctpr_mask;
+ env->mmuregs[reg] = val & env->def->mmu_ctpr_mask;
break;
case 2: // Context Register
- env->mmuregs[reg] = val & env->mmu_cxr_mask;
+ env->mmuregs[reg] = val & env->def->mmu_cxr_mask;
if (oldreg != env->mmuregs[reg]) {
/* we flush when the MMU context changes because
QEMU has no MMU context support */
case 4: // Synchronous Fault Address Register
break;
case 0x10: // TLB Replacement Control Register
- env->mmuregs[reg] = val & env->mmu_trcr_mask;
+ env->mmuregs[reg] = val & env->def->mmu_trcr_mask;
break;
case 0x13: // Synchronous Fault Status Register with Read and Clear
- env->mmuregs[3] = val & env->mmu_sfsr_mask;
+ env->mmuregs[3] = val & env->def->mmu_sfsr_mask;
break;
case 0x14: // Synchronous Fault Address Register
env->mmuregs[4] = val;
raise_exception(TT_PRIV_ACT);
helper_check_align(addr, size - 1);
- ABI32_MASK(addr);
+ address_mask(env, &addr);
switch (asi) {
case 0x80: // Primary
raise_exception(TT_PRIV_ACT);
helper_check_align(addr, size - 1);
- ABI32_MASK(addr);
+ address_mask(env, &addr);
/* Convert to little endian */
switch (asi) {
#endif
if ((asi < 0x80 && (env->pstate & PS_PRIV) == 0)
- || (asi >= 0x30 && asi < 0x80 && !(env->hpstate & HS_PRIV)))
+ || ((env->def->features & CPU_FEATURE_HYPV)
+ && asi >= 0x30 && asi < 0x80
+ && !(env->hpstate & HS_PRIV)))
raise_exception(TT_PRIV_ACT);
helper_check_align(addr, size - 1);
case 0x88: // Primary LE
case 0x8a: // Primary no-fault LE
if ((asi & 0x80) && (env->pstate & PS_PRIV)) {
- if (env->hpstate & HS_PRIV) {
+ if ((env->def->features & CPU_FEATURE_HYPV)
+ && env->hpstate & HS_PRIV) {
switch(size) {
case 1:
ret = ldub_hypv(addr);
}
break;
}
+ case 0x24: // Nucleus quad LDD 128 bit atomic
+ case 0x2c: // Nucleus quad LDD 128 bit atomic LE
+ // Only ldda allowed
+ raise_exception(TT_ILL_INSN);
+ return 0;
case 0x04: // Nucleus
case 0x0c: // Nucleus Little Endian (LE)
case 0x11: // As if user secondary
case 0x19: // As if user secondary LE
- case 0x24: // Nucleus quad LDD 128 bit atomic
- case 0x2c: // Nucleus quad LDD 128 bit atomic
case 0x4a: // UPA config
case 0x81: // Secondary
case 0x83: // Secondary no-fault
}
case 0x51: // I-MMU 8k TSB pointer
case 0x52: // I-MMU 64k TSB pointer
- case 0x55: // I-MMU data access
// XXX
break;
+ case 0x55: // I-MMU data access
+ {
+ int reg = (addr >> 3) & 0x3f;
+
+ ret = env->itlb_tte[reg];
+ break;
+ }
case 0x56: // I-MMU tag read
{
- unsigned int i;
+ int reg = (addr >> 3) & 0x3f;
- for (i = 0; i < 64; i++) {
- // Valid, ctx match, vaddr match
- if ((env->itlb_tte[i] & 0x8000000000000000ULL) != 0 &&
- env->itlb_tag[i] == addr) {
- ret = env->itlb_tag[i];
- break;
- }
- }
+ ret = env->itlb_tag[reg];
break;
}
case 0x58: // D-MMU regs
ret = env->dmmuregs[reg];
break;
}
+ case 0x5d: // D-MMU data access
+ {
+ int reg = (addr >> 3) & 0x3f;
+
+ ret = env->dtlb_tte[reg];
+ break;
+ }
case 0x5e: // D-MMU tag read
{
- unsigned int i;
+ int reg = (addr >> 3) & 0x3f;
- for (i = 0; i < 64; i++) {
- // Valid, ctx match, vaddr match
- if ((env->dtlb_tte[i] & 0x8000000000000000ULL) != 0 &&
- env->dtlb_tag[i] == addr) {
- ret = env->dtlb_tag[i];
- break;
- }
- }
+ ret = env->dtlb_tag[reg];
break;
}
+ case 0x46: // D-cache data
+ case 0x47: // D-cache tag access
+ case 0x4b: // E-cache error enable
+ case 0x4c: // E-cache asynchronous fault status
+ case 0x4d: // E-cache asynchronous fault address
+ case 0x4e: // E-cache tag data
+ case 0x66: // I-cache instruction access
+ case 0x67: // I-cache tag access
+ case 0x6e: // I-cache predecode
+ case 0x6f: // I-cache LRU etc.
+ case 0x76: // E-cache tag
+ case 0x7e: // E-cache tag
+ break;
case 0x59: // D-MMU 8k TSB pointer
case 0x5a: // D-MMU 64k TSB pointer
case 0x5b: // D-MMU data pointer
- case 0x5d: // D-MMU data access
case 0x48: // Interrupt dispatch, RO
case 0x49: // Interrupt data receive
case 0x7f: // Incoming interrupt vector, RO
dump_asi("write", addr, asi, size, val);
#endif
if ((asi < 0x80 && (env->pstate & PS_PRIV) == 0)
- || (asi >= 0x30 && asi < 0x80 && !(env->hpstate & HS_PRIV)))
+ || ((env->def->features & CPU_FEATURE_HYPV)
+ && asi >= 0x30 && asi < 0x80
+ && !(env->hpstate & HS_PRIV)))
raise_exception(TT_PRIV_ACT);
helper_check_align(addr, size - 1);
case 0x80: // Primary
case 0x88: // Primary LE
if ((asi & 0x80) && (env->pstate & PS_PRIV)) {
- if (env->hpstate & HS_PRIV) {
+ if ((env->def->features & CPU_FEATURE_HYPV)
+ && env->hpstate & HS_PRIV) {
switch(size) {
case 1:
stb_hypv(addr, val);
}
}
return;
+ case 0x24: // Nucleus quad LDD 128 bit atomic
+ case 0x2c: // Nucleus quad LDD 128 bit atomic LE
+ // Only ldda allowed
+ raise_exception(TT_ILL_INSN);
+ return;
case 0x04: // Nucleus
case 0x0c: // Nucleus Little Endian (LE)
case 0x11: // As if user secondary
case 0x19: // As if user secondary LE
- case 0x24: // Nucleus quad LDD 128 bit atomic
- case 0x2c: // Nucleus quad LDD 128 bit atomic
case 0x4a: // UPA config
case 0x81: // Secondary
case 0x89: // Secondary LE
case 0x49: // Interrupt data receive
// XXX
return;
+ case 0x46: // D-cache data
+ case 0x47: // D-cache tag access
+ case 0x4b: // E-cache error enable
+ case 0x4c: // E-cache asynchronous fault status
+ case 0x4d: // E-cache asynchronous fault address
+ case 0x4e: // E-cache tag data
+ case 0x66: // I-cache instruction access
+ case 0x67: // I-cache tag access
+ case 0x6e: // I-cache predecode
+ case 0x6f: // I-cache LRU etc.
+ case 0x76: // E-cache tag
+ case 0x7e: // E-cache tag
+ return;
case 0x51: // I-MMU 8k TSB pointer, RO
case 0x52: // I-MMU 64k TSB pointer, RO
case 0x56: // I-MMU tag read, RO
}
#endif /* CONFIG_USER_ONLY */
+void helper_ldda_asi(target_ulong addr, int asi, int rd)
+{
+ if ((asi < 0x80 && (env->pstate & PS_PRIV) == 0)
+ || ((env->def->features & CPU_FEATURE_HYPV)
+ && asi >= 0x30 && asi < 0x80
+ && !(env->hpstate & HS_PRIV)))
+ raise_exception(TT_PRIV_ACT);
+
+ switch (asi) {
+ case 0x24: // Nucleus quad LDD 128 bit atomic
+ case 0x2c: // Nucleus quad LDD 128 bit atomic LE
+ helper_check_align(addr, 0xf);
+ if (rd == 0) {
+ env->gregs[1] = ldq_kernel(addr + 8);
+ if (asi == 0x2c)
+ bswap64s(&env->gregs[1]);
+ } else if (rd < 8) {
+ env->gregs[rd] = ldq_kernel(addr);
+ env->gregs[rd + 1] = ldq_kernel(addr + 8);
+ if (asi == 0x2c) {
+ bswap64s(&env->gregs[rd]);
+ bswap64s(&env->gregs[rd + 1]);
+ }
+ } else {
+ env->regwptr[rd] = ldq_kernel(addr);
+ env->regwptr[rd + 1] = ldq_kernel(addr + 8);
+ if (asi == 0x2c) {
+ bswap64s(&env->regwptr[rd]);
+ bswap64s(&env->regwptr[rd + 1]);
+ }
+ }
+ break;
+ default:
+ helper_check_align(addr, 0x3);
+ if (rd == 0)
+ env->gregs[1] = helper_ld_asi(addr + 4, asi, 4, 0);
+ else if (rd < 8) {
+ env->gregs[rd] = helper_ld_asi(addr, asi, 4, 0);
+ env->gregs[rd + 1] = helper_ld_asi(addr + 4, asi, 4, 0);
+ } else {
+ env->regwptr[rd] = helper_ld_asi(addr, asi, 4, 0);
+ env->regwptr[rd + 1] = helper_ld_asi(addr + 4, asi, 4, 0);
+ }
+ break;
+ }
+}
+
void helper_ldf_asi(target_ulong addr, int asi, int size, int rd)
{
unsigned int i;
raise_exception(TT_ILL_INSN);
env->psret = 1;
- cwp = (env->cwp + 1) & (NWINDOWS - 1);
+ cwp = cpu_cwp_inc(env, env->cwp + 1) ;
if (env->wim & (1 << cwp)) {
raise_exception(TT_WIN_UNF);
}
uint64_t x0;
uint32_t x1;
- x0 = a | ((uint64_t) (env->y) << 32);
+ x0 = (a & 0xffffffff) | ((int64_t) (env->y) << 32);
x1 = b;
if (x1 == 0) {
int64_t x0;
int32_t x1;
- x0 = a | ((int64_t) (env->y) << 32);
+ x0 = (a & 0xffffffff) | ((int64_t) (env->y) << 32);
x1 = b;
if (x1 == 0) {
break;
}
#else
- ABI32_MASK(addr);
+ address_mask(env, &addr);
stfq_raw(addr, DT0);
#endif
}
break;
}
#else
- ABI32_MASK(addr);
+ address_mask(env, &addr);
DT0 = ldfq_raw(addr);
#endif
}
break;
}
#else
- ABI32_MASK(addr);
+ address_mask(env, &addr);
u.ll.upper = ldq_raw(addr);
u.ll.lower = ldq_raw((addr + 8) & 0xffffffffULL);
QT0 = u.q;
}
#else
u.q = QT0;
- ABI32_MASK(addr);
+ address_mask(env, &addr);
stq_raw(addr, u.ll.upper);
stq_raw((addr + 8) & 0xffffffffULL, u.ll.lower);
#endif
{
uint32_t cwp;
- cwp = (env->cwp - 1) & (NWINDOWS - 1);
+ cwp = cpu_cwp_dec(env, env->cwp - 1);
if (env->wim & (1 << cwp)) {
raise_exception(TT_WIN_OVF);
}
{
uint32_t cwp;
- cwp = (env->cwp + 1) & (NWINDOWS - 1);
+ cwp = cpu_cwp_inc(env, env->cwp + 1);
if (env->wim & (1 << cwp)) {
raise_exception(TT_WIN_UNF);
}
void helper_wrpsr(target_ulong new_psr)
{
- if ((new_psr & PSR_CWP) >= NWINDOWS)
+ if ((new_psr & PSR_CWP) >= env->nwindows)
raise_exception(TT_ILL_INSN);
else
PUT_PSR(env, new_psr);
{
uint32_t cwp;
- cwp = (env->cwp - 1) & (NWINDOWS - 1);
+ cwp = cpu_cwp_dec(env, env->cwp - 1);
if (env->cansave == 0) {
raise_exception(TT_SPILL | (env->otherwin != 0 ?
(TT_WOTHER | ((env->wstate & 0x38) >> 1)):
{
uint32_t cwp;
- cwp = (env->cwp + 1) & (NWINDOWS - 1);
+ cwp = cpu_cwp_inc(env, env->cwp + 1);
if (env->canrestore == 0) {
raise_exception(TT_FILL | (env->otherwin != 0 ?
(TT_WOTHER | ((env->wstate & 0x38) >> 1)):
void helper_flushw(void)
{
- if (env->cansave != NWINDOWS - 2) {
+ if (env->cansave != env->nwindows - 2) {
raise_exception(TT_SPILL | (env->otherwin != 0 ?
(TT_WOTHER | ((env->wstate & 0x38) >> 1)):
((env->wstate & 0x7) << 2)));
void helper_restored(void)
{
env->canrestore++;
- if (env->cleanwin < NWINDOWS - 1)
+ if (env->cleanwin < env->nwindows - 1)
env->cleanwin++;
if (env->otherwin == 0)
env->cansave--;
void helper_wrpstate(target_ulong new_state)
{
- change_pstate(new_state & 0xf3f);
+ if (!(env->def->features & CPU_FEATURE_GL))
+ change_pstate(new_state & 0xf3f);
}
void helper_done(void)
{
- env->tl--;
- env->tsptr = &env->ts[env->tl];
env->pc = env->tsptr->tpc;
env->npc = env->tsptr->tnpc + 4;
PUT_CCR(env, env->tsptr->tstate >> 32);
env->asi = (env->tsptr->tstate >> 24) & 0xff;
change_pstate((env->tsptr->tstate >> 8) & 0xf3f);
PUT_CWP64(env, env->tsptr->tstate & 0xff);
+ env->tl--;
+ env->tsptr = &env->ts[env->tl & MAXTL_MASK];
}
void helper_retry(void)
{
- env->tl--;
- env->tsptr = &env->ts[env->tl];
env->pc = env->tsptr->tpc;
env->npc = env->tsptr->tnpc;
PUT_CCR(env, env->tsptr->tstate >> 32);
env->asi = (env->tsptr->tstate >> 24) & 0xff;
change_pstate((env->tsptr->tstate >> 8) & 0xf3f);
PUT_CWP64(env, env->tsptr->tstate & 0xff);
+ env->tl--;
+ env->tsptr = &env->ts[env->tl & MAXTL_MASK];
}
#endif
-void set_cwp(int new_cwp)
+void helper_flush(target_ulong addr)
{
- /* put the modified wrap registers at their proper location */
- if (env->cwp == (NWINDOWS - 1))
- memcpy32(env->regbase, env->regbase + NWINDOWS * 16);
- env->cwp = new_cwp;
- /* put the wrap registers at their temporary location */
- if (new_cwp == (NWINDOWS - 1))
- memcpy32(env->regbase + NWINDOWS * 16, env->regbase);
- env->regwptr = env->regbase + (new_cwp * 16);
- REGWPTR = env->regwptr;
-}
-
-void cpu_set_cwp(CPUState *env1, int new_cwp)
-{
- CPUState *saved_env;
-#ifdef reg_REGWPTR
- target_ulong *saved_regwptr;
-#endif
-
- saved_env = env;
-#ifdef reg_REGWPTR
- saved_regwptr = REGWPTR;
-#endif
- env = env1;
- set_cwp(new_cwp);
- env = saved_env;
-#ifdef reg_REGWPTR
- REGWPTR = saved_regwptr;
-#endif
+ addr &= ~7;
+ tb_invalidate_page_range(addr, addr + 8);
}
#ifdef TARGET_SPARC64
#ifdef DEBUG_PCALL
-static const char * const excp_names[0x50] = {
+static const char * const excp_names[0x80] = {
[TT_TFAULT] = "Instruction Access Fault",
[TT_TMISS] = "Instruction Access MMU Miss",
[TT_CODE_ACCESS] = "Instruction Access Error",
};
#endif
-void do_interrupt(int intno)
+void do_interrupt(CPUState *env)
{
+ int intno = env->exception_index;
+
#ifdef DEBUG_PCALL
if (loglevel & CPU_LOG_INT) {
static int count;
const char *name;
- if (intno < 0 || intno >= 0x180 || (intno > 0x4f && intno < 0x80))
+ if (intno < 0 || intno >= 0x180)
name = "Unknown";
else if (intno >= 0x100)
name = "Trap Instruction";
}
#endif
#if !defined(CONFIG_USER_ONLY)
- if (env->tl == MAXTL) {
- cpu_abort(env, "Trap 0x%04x while trap level is MAXTL, Error state",
- env->exception_index);
+ if (env->tl >= env->maxtl) {
+ cpu_abort(env, "Trap 0x%04x while trap level (%d) >= MAXTL (%d),"
+ " Error state", env->exception_index, env->tl, env->maxtl);
return;
}
#endif
+ if (env->tl < env->maxtl - 1) {
+ env->tl++;
+ } else {
+ env->pstate |= PS_RED;
+ if (env->tl < env->maxtl)
+ env->tl++;
+ }
+ env->tsptr = &env->ts[env->tl & MAXTL_MASK];
env->tsptr->tstate = ((uint64_t)GET_CCR(env) << 32) |
((env->asi & 0xff) << 24) | ((env->pstate & 0xf3f) << 8) |
GET_CWP64(env);
env->tsptr->tpc = env->pc;
env->tsptr->tnpc = env->npc;
env->tsptr->tt = intno;
- change_pstate(PS_PEF | PS_PRIV | PS_AG);
-
+ if (!(env->def->features & CPU_FEATURE_GL)) {
+ switch (intno) {
+ case TT_IVEC:
+ change_pstate(PS_PEF | PS_PRIV | PS_IG);
+ break;
+ case TT_TFAULT:
+ case TT_TMISS:
+ case TT_DFAULT:
+ case TT_DMISS:
+ case TT_DPROT:
+ change_pstate(PS_PEF | PS_PRIV | PS_MG);
+ break;
+ default:
+ change_pstate(PS_PEF | PS_PRIV | PS_AG);
+ break;
+ }
+ }
if (intno == TT_CLRWIN)
- set_cwp((env->cwp - 1) & (NWINDOWS - 1));
+ cpu_set_cwp(env, cpu_cwp_dec(env, env->cwp - 1));
else if ((intno & 0x1c0) == TT_SPILL)
- set_cwp((env->cwp - env->cansave - 2) & (NWINDOWS - 1));
+ cpu_set_cwp(env, cpu_cwp_dec(env, env->cwp - env->cansave - 2));
else if ((intno & 0x1c0) == TT_FILL)
- set_cwp((env->cwp + 1) & (NWINDOWS - 1));
+ cpu_set_cwp(env, cpu_cwp_inc(env, env->cwp + 1));
env->tbr &= ~0x7fffULL;
env->tbr |= ((env->tl > 1) ? 1 << 14 : 0) | (intno << 5);
- if (env->tl < MAXTL - 1) {
- env->tl++;
- } else {
- env->pstate |= PS_RED;
- if (env->tl != MAXTL)
- env->tl++;
- }
- env->tsptr = &env->ts[env->tl];
env->pc = env->tbr;
env->npc = env->pc + 4;
env->exception_index = 0;
};
#endif
-void do_interrupt(int intno)
+void do_interrupt(CPUState *env)
{
- int cwp;
+ int cwp, intno = env->exception_index;
#ifdef DEBUG_PCALL
if (loglevel & CPU_LOG_INT) {
}
#endif
env->psret = 0;
- cwp = (env->cwp - 1) & (NWINDOWS - 1);
- set_cwp(cwp);
+ cwp = cpu_cwp_dec(env, env->cwp - 1);
+ cpu_set_cwp(env, cwp);
env->regwptr[9] = env->pc;
env->regwptr[10] = env->npc;
env->psrps = env->psrs;