#include "exec.h"
+#include "host-utils.h"
//#define DEBUG_PCALL
//#define DEBUG_MMU
+//#define DEBUG_MXCC
//#define DEBUG_UNALIGNED
//#define DEBUG_UNASSIGNED
+#ifdef DEBUG_MMU
+#define DPRINTF_MMU(fmt, args...) \
+do { printf("MMU: " fmt , ##args); } while (0)
+#else
+#define DPRINTF_MMU(fmt, args...)
+#endif
+
+#ifdef DEBUG_MXCC
+#define DPRINTF_MXCC(fmt, args...) \
+do { printf("MXCC: " fmt , ##args); } while (0)
+#else
+#define DPRINTF_MXCC(fmt, args...)
+#endif
+
void raise_exception(int tt)
{
env->exception_index = tt;
{
DT0 = int32_to_float64(*((int32_t *)&FT1), &env->fp_status);
}
+#ifdef TARGET_SPARC64
+void do_fxtos(void)
+{
+ set_float_exception_flags(0, &env->fp_status);
+ FT0 = int64_to_float32(*((int64_t *)&DT1), &env->fp_status);
+ check_ieee_exceptions();
+}
+
+void do_fxtod(void)
+{
+ set_float_exception_flags(0, &env->fp_status);
+ DT0 = int64_to_float64(*((int64_t *)&DT1), &env->fp_status);
+ check_ieee_exceptions();
+}
+#endif
#endif
void do_fabss(void)
GEN_FCMP(fcmped_fcc3, float64, DT0, DT1, 26, 1);
#endif
-#if defined(CONFIG_USER_ONLY)
-void helper_ld_asi(int asi, int size, int sign)
-{
-}
+#ifndef TARGET_SPARC64
+#ifndef CONFIG_USER_ONLY
-void helper_st_asi(int asi, int size, int sign)
+#ifdef DEBUG_MXCC
+static void dump_mxcc(CPUState *env)
{
+ printf("mxccdata: %016llx %016llx %016llx %016llx\n",
+ env->mxccdata[0], env->mxccdata[1], env->mxccdata[2], env->mxccdata[3]);
+ printf("mxccregs: %016llx %016llx %016llx %016llx\n"
+ " %016llx %016llx %016llx %016llx\n",
+ env->mxccregs[0], env->mxccregs[1], env->mxccregs[2], env->mxccregs[3],
+ env->mxccregs[4], env->mxccregs[5], env->mxccregs[6], env->mxccregs[7]);
}
-#else
-#ifndef TARGET_SPARC64
+#endif
+
void helper_ld_asi(int asi, int size, int sign)
{
uint32_t ret = 0;
+ uint64_t tmp;
+#ifdef DEBUG_MXCC
+ uint32_t last_T0 = T0;
+#endif
switch (asi) {
case 2: /* SuperSparc MXCC registers */
+ switch (T0) {
+ case 0x01c00a00: /* MXCC control register */
+ if (size == 8) {
+ ret = env->mxccregs[3];
+ T0 = env->mxccregs[3] >> 32;
+ } else
+ DPRINTF_MXCC("%08x: unimplemented access size: %d\n", T0, size);
+ break;
+ case 0x01c00a04: /* MXCC control register */
+ if (size == 4)
+ ret = env->mxccregs[3];
+ else
+ DPRINTF_MXCC("%08x: unimplemented access size: %d\n", T0, size);
+ break;
+ case 0x01c00c00: /* Module reset register */
+ if (size == 8) {
+ ret = env->mxccregs[5] >> 32;
+ T0 = env->mxccregs[5];
+ // should we do something here?
+ } else
+ DPRINTF_MXCC("%08x: unimplemented access size: %d\n", T0, size);
+ break;
+ case 0x01c00f00: /* MBus port address register */
+ if (size == 8) {
+ ret = env->mxccregs[7];
+ T0 = env->mxccregs[7] >> 32;
+ } else
+ DPRINTF_MXCC("%08x: unimplemented access size: %d\n", T0, size);
+ break;
+ default:
+ DPRINTF_MXCC("%08x: unimplemented address, size: %d\n", T0, size);
+ break;
+ }
+ DPRINTF_MXCC("asi = %d, size = %d, sign = %d, T0 = %08x -> ret = %08x,"
+ "T0 = %08x\n", asi, size, sign, last_T0, ret, T0);
+#ifdef DEBUG_MXCC
+ dump_mxcc(env);
+#endif
break;
case 3: /* MMU probe */
{
ret = mmu_probe(env, T0, mmulev);
//bswap32s(&ret);
}
-#ifdef DEBUG_MMU
- printf("mmu_probe: 0x%08x (lev %d) -> 0x%08x\n", T0, mmulev, ret);
-#endif
+ DPRINTF_MMU("mmu_probe: 0x%08x (lev %d) -> 0x%08x\n", T0, mmulev, ret);
}
break;
case 4: /* read MMU regs */
ret = env->mmuregs[reg];
if (reg == 3) /* Fault status cleared on read */
env->mmuregs[reg] = 0;
-#ifdef DEBUG_MMU
- printf("mmu_read: reg[%d] = 0x%08x\n", reg, ret);
-#endif
+ DPRINTF_MMU("mmu_read: reg[%d] = 0x%08x\n", reg, ret);
}
break;
case 9: /* Supervisor code access */
ret = ldl_code(T0 & ~3);
break;
case 8:
- ret = ldl_code(T0 & ~3);
- T0 = ldl_code((T0 + 4) & ~3);
+ tmp = ldq_code(T0 & ~7);
+ ret = tmp >> 32;
+ T0 = tmp;
+ break;
+ }
+ break;
+ case 0xa: /* User data access */
+ switch(size) {
+ case 1:
+ ret = ldub_user(T0);
+ break;
+ case 2:
+ ret = lduw_user(T0 & ~1);
+ break;
+ default:
+ case 4:
+ ret = ldl_user(T0 & ~3);
+ break;
+ case 8:
+ tmp = ldq_user(T0 & ~7);
+ ret = tmp >> 32;
+ T0 = tmp;
+ break;
+ }
+ break;
+ case 0xb: /* Supervisor data access */
+ switch(size) {
+ case 1:
+ ret = ldub_kernel(T0);
+ break;
+ case 2:
+ ret = lduw_kernel(T0 & ~1);
+ break;
+ default:
+ case 4:
+ ret = ldl_kernel(T0 & ~3);
+ break;
+ case 8:
+ tmp = ldq_kernel(T0 & ~7);
+ ret = tmp >> 32;
+ T0 = tmp;
break;
}
break;
ret = ldl_phys(T0 & ~3);
break;
case 8:
- ret = ldl_phys(T0 & ~3);
- T0 = ldl_phys((T0 + 4) & ~3);
+ tmp = ldq_phys(T0 & ~7);
+ ret = tmp >> 32;
+ T0 = tmp;
break;
}
break;
| ((target_phys_addr_t)(asi & 0xf) << 32));
break;
case 8:
- ret = ldl_phys((target_phys_addr_t)(T0 & ~3)
- | ((target_phys_addr_t)(asi & 0xf) << 32));
- T0 = ldl_phys((target_phys_addr_t)((T0 + 4) & ~3)
+ tmp = ldq_phys((target_phys_addr_t)(T0 & ~7)
| ((target_phys_addr_t)(asi & 0xf) << 32));
+ ret = tmp >> 32;
+ T0 = tmp;
break;
}
break;
ret = 0;
break;
}
- T1 = ret;
+ if (sign) {
+ switch(size) {
+ case 1:
+ T1 = (int8_t) ret;
+ break;
+ case 2:
+ T1 = (int16_t) ret;
+ break;
+ default:
+ T1 = ret;
+ break;
+ }
+ }
+ else
+ T1 = ret;
}
-void helper_st_asi(int asi, int size, int sign)
+void helper_st_asi(int asi, int size)
{
switch(asi) {
case 2: /* SuperSparc MXCC registers */
+ switch (T0) {
+ case 0x01c00000: /* MXCC stream data register 0 */
+ if (size == 8)
+ env->mxccdata[0] = ((uint64_t)T1 << 32) | T2;
+ else
+ DPRINTF_MXCC("%08x: unimplemented access size: %d\n", T0, size);
+ break;
+ case 0x01c00008: /* MXCC stream data register 1 */
+ if (size == 8)
+ env->mxccdata[1] = ((uint64_t)T1 << 32) | T2;
+ else
+ DPRINTF_MXCC("%08x: unimplemented access size: %d\n", T0, size);
+ break;
+ case 0x01c00010: /* MXCC stream data register 2 */
+ if (size == 8)
+ env->mxccdata[2] = ((uint64_t)T1 << 32) | T2;
+ else
+ DPRINTF_MXCC("%08x: unimplemented access size: %d\n", T0, size);
+ break;
+ case 0x01c00018: /* MXCC stream data register 3 */
+ if (size == 8)
+ env->mxccdata[3] = ((uint64_t)T1 << 32) | T2;
+ else
+ DPRINTF_MXCC("%08x: unimplemented access size: %d\n", T0, size);
+ break;
+ case 0x01c00100: /* MXCC stream source */
+ if (size == 8)
+ env->mxccregs[0] = ((uint64_t)T1 << 32) | T2;
+ else
+ DPRINTF_MXCC("%08x: unimplemented access size: %d\n", T0, size);
+ env->mxccdata[0] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) + 0);
+ env->mxccdata[1] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) + 8);
+ env->mxccdata[2] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) + 16);
+ env->mxccdata[3] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) + 24);
+ break;
+ case 0x01c00200: /* MXCC stream destination */
+ if (size == 8)
+ env->mxccregs[1] = ((uint64_t)T1 << 32) | T2;
+ else
+ DPRINTF_MXCC("%08x: unimplemented access size: %d\n", T0, size);
+ stq_phys((env->mxccregs[1] & 0xffffffffULL) + 0, env->mxccdata[0]);
+ stq_phys((env->mxccregs[1] & 0xffffffffULL) + 8, env->mxccdata[1]);
+ stq_phys((env->mxccregs[1] & 0xffffffffULL) + 16, env->mxccdata[2]);
+ stq_phys((env->mxccregs[1] & 0xffffffffULL) + 24, env->mxccdata[3]);
+ break;
+ case 0x01c00a00: /* MXCC control register */
+ if (size == 8)
+ env->mxccregs[3] = ((uint64_t)T1 << 32) | T2;
+ else
+ DPRINTF_MXCC("%08x: unimplemented access size: %d\n", T0, size);
+ break;
+ case 0x01c00a04: /* MXCC control register */
+ if (size == 4)
+ env->mxccregs[3] = (env->mxccregs[0xa] & 0xffffffff00000000ULL) | T1;
+ else
+ DPRINTF_MXCC("%08x: unimplemented access size: %d\n", T0, size);
+ break;
+ case 0x01c00e00: /* MXCC error register */
+ // writing a 1 bit clears the error
+ if (size == 8)
+ env->mxccregs[6] &= ~(((uint64_t)T1 << 32) | T2);
+ else
+ DPRINTF_MXCC("%08x: unimplemented access size: %d\n", T0, size);
+ break;
+ case 0x01c00f00: /* MBus port address register */
+ if (size == 8)
+ env->mxccregs[7] = ((uint64_t)T1 << 32) | T2;
+ else
+ DPRINTF_MXCC("%08x: unimplemented access size: %d\n", T0, size);
+ break;
+ default:
+ DPRINTF_MXCC("%08x: unimplemented address, size: %d\n", T0, size);
+ break;
+ }
+ DPRINTF_MXCC("asi = %d, size = %d, T0 = %08x, T1 = %08x\n", asi, size, T0, T1);
+#ifdef DEBUG_MXCC
+ dump_mxcc(env);
+#endif
break;
case 3: /* MMU flush */
{
int mmulev;
mmulev = (T0 >> 8) & 15;
-#ifdef DEBUG_MMU
- printf("mmu flush level %d\n", mmulev);
-#endif
+ DPRINTF_MMU("mmu flush level %d\n", mmulev);
switch (mmulev) {
case 0: // flush page
tlb_flush_page(env, T0 & 0xfffff000);
oldreg = env->mmuregs[reg];
switch(reg) {
case 0:
- env->mmuregs[reg] &= ~(MMU_E | MMU_NF);
- env->mmuregs[reg] |= T1 & (MMU_E | MMU_NF);
+ env->mmuregs[reg] &= ~(MMU_E | MMU_NF | env->mmu_bm);
+ env->mmuregs[reg] |= T1 & (MMU_E | MMU_NF | env->mmu_bm);
// Mappings generated during no-fault mode or MMU
// disabled mode are invalid in normal mode
if (oldreg != env->mmuregs[reg])
env->mmuregs[reg] = T1;
break;
}
-#ifdef DEBUG_MMU
if (oldreg != env->mmuregs[reg]) {
- printf("mmu change reg[%d]: 0x%08x -> 0x%08x\n", reg, oldreg, env->mmuregs[reg]);
+ DPRINTF_MMU("mmu change reg[%d]: 0x%08x -> 0x%08x\n", reg, oldreg, env->mmuregs[reg]);
}
+#ifdef DEBUG_MMU
dump_mmu(env);
#endif
return;
}
+ case 0xa: /* User data access */
+ switch(size) {
+ case 1:
+ stb_user(T0, T1);
+ break;
+ case 2:
+ stw_user(T0 & ~1, T1);
+ break;
+ default:
+ case 4:
+ stl_user(T0 & ~3, T1);
+ break;
+ case 8:
+ stq_user(T0 & ~7, ((uint64_t)T1 << 32) | T2);
+ break;
+ }
+ break;
+ case 0xb: /* Supervisor data access */
+ switch(size) {
+ case 1:
+ stb_kernel(T0, T1);
+ break;
+ case 2:
+ stw_kernel(T0 & ~1, T1);
+ break;
+ default:
+ case 4:
+ stl_kernel(T0 & ~3, T1);
+ break;
+ case 8:
+ stq_kernel(T0 & ~7, ((uint64_t)T1 << 32) | T2);
+ break;
+ }
+ break;
case 0xc: /* I-cache tag */
case 0xd: /* I-cache data */
case 0xe: /* D-cache tag */
stl_phys(T0 & ~3, T1);
break;
case 8:
- stl_phys(T0 & ~3, T1);
- stl_phys((T0 + 4) & ~3, T2);
+ stq_phys(T0 & ~7, ((uint64_t)T1 << 32) | T2);
break;
}
}
| ((target_phys_addr_t)(asi & 0xf) << 32), T1);
break;
case 8:
- stl_phys((target_phys_addr_t)(T0 & ~3)
- | ((target_phys_addr_t)(asi & 0xf) << 32), T1);
- stl_phys((target_phys_addr_t)((T0 + 4) & ~3)
- | ((target_phys_addr_t)(asi & 0xf) << 32), T1);
+ stq_phys((target_phys_addr_t)(T0 & ~7)
+ | ((target_phys_addr_t)(asi & 0xf) << 32),
+ ((uint64_t)T1 << 32) | T2);
break;
}
}
}
}
-#else
+#endif /* CONFIG_USER_ONLY */
+#else /* TARGET_SPARC64 */
+#ifdef CONFIG_USER_ONLY
void helper_ld_asi(int asi, int size, int sign)
{
uint64_t ret = 0;
- if (asi < 0x80 && (env->pstate & PS_PRIV) == 0)
+ if (asi < 0x80)
raise_exception(TT_PRIV_ACT);
switch (asi) {
+ case 0x80: // Primary
+ case 0x82: // Primary no-fault
+ case 0x88: // Primary LE
+ case 0x8a: // Primary no-fault LE
+ {
+ switch(size) {
+ case 1:
+ ret = ldub_raw(T0);
+ break;
+ case 2:
+ ret = lduw_raw(T0 & ~1);
+ break;
+ case 4:
+ ret = ldl_raw(T0 & ~3);
+ break;
+ default:
+ case 8:
+ ret = ldq_raw(T0 & ~7);
+ break;
+ }
+ }
+ break;
+ case 0x81: // Secondary
+ case 0x83: // Secondary no-fault
+ case 0x89: // Secondary LE
+ case 0x8b: // Secondary no-fault LE
+ // XXX
+ break;
+ default:
+ break;
+ }
+
+ /* Convert from little endian */
+ switch (asi) {
+ case 0x88: // Primary LE
+ case 0x89: // Secondary LE
+ case 0x8a: // Primary no-fault LE
+ case 0x8b: // Secondary no-fault LE
+ switch(size) {
+ case 2:
+ ret = bswap16(ret);
+ break;
+ case 4:
+ ret = bswap32(ret);
+ break;
+ case 8:
+ ret = bswap64(ret);
+ break;
+ default:
+ break;
+ }
+ default:
+ break;
+ }
+
+ /* Convert to signed number */
+ if (sign) {
+ switch(size) {
+ case 1:
+ ret = (int8_t) ret;
+ break;
+ case 2:
+ ret = (int16_t) ret;
+ break;
+ case 4:
+ ret = (int32_t) ret;
+ break;
+ default:
+ break;
+ }
+ }
+ T1 = ret;
+}
+
+void helper_st_asi(int asi, int size)
+{
+ if (asi < 0x80)
+ raise_exception(TT_PRIV_ACT);
+
+ /* Convert to little endian */
+ switch (asi) {
+ case 0x88: // Primary LE
+ case 0x89: // Secondary LE
+ switch(size) {
+ case 2:
+ T0 = bswap16(T0);
+ break;
+ case 4:
+ T0 = bswap32(T0);
+ break;
+ case 8:
+ T0 = bswap64(T0);
+ break;
+ default:
+ break;
+ }
+ default:
+ break;
+ }
+
+ switch(asi) {
+ case 0x80: // Primary
+ case 0x88: // Primary LE
+ {
+ switch(size) {
+ case 1:
+ stb_raw(T0, T1);
+ break;
+ case 2:
+ stw_raw(T0 & ~1, T1);
+ break;
+ case 4:
+ stl_raw(T0 & ~3, T1);
+ break;
+ case 8:
+ default:
+ stq_raw(T0 & ~7, T1);
+ break;
+ }
+ }
+ break;
+ case 0x81: // Secondary
+ case 0x89: // Secondary LE
+ // XXX
+ return;
+
+ case 0x82: // Primary no-fault, RO
+ case 0x83: // Secondary no-fault, RO
+ case 0x8a: // Primary no-fault LE, RO
+ case 0x8b: // Secondary no-fault LE, RO
+ default:
+ do_unassigned_access(T0, 1, 0, 1);
+ return;
+ }
+}
+
+#else /* CONFIG_USER_ONLY */
+
+void helper_ld_asi(int asi, int size, int sign)
+{
+ uint64_t ret = 0;
+
+ if ((asi < 0x80 && (env->pstate & PS_PRIV) == 0)
+ || (asi >= 0x30 && asi < 0x80 && !(env->hpstate & HS_PRIV)))
+ raise_exception(TT_PRIV_ACT);
+
+ switch (asi) {
+ case 0x10: // As if user primary
+ case 0x18: // As if user primary LE
+ case 0x80: // Primary
+ case 0x82: // Primary no-fault
+ case 0x88: // Primary LE
+ case 0x8a: // Primary no-fault LE
+ if ((asi & 0x80) && (env->pstate & PS_PRIV)) {
+ if (env->hpstate & HS_PRIV) {
+ switch(size) {
+ case 1:
+ ret = ldub_hypv(T0);
+ break;
+ case 2:
+ ret = lduw_hypv(T0 & ~1);
+ break;
+ case 4:
+ ret = ldl_hypv(T0 & ~3);
+ break;
+ default:
+ case 8:
+ ret = ldq_hypv(T0 & ~7);
+ break;
+ }
+ } else {
+ switch(size) {
+ case 1:
+ ret = ldub_kernel(T0);
+ break;
+ case 2:
+ ret = lduw_kernel(T0 & ~1);
+ break;
+ case 4:
+ ret = ldl_kernel(T0 & ~3);
+ break;
+ default:
+ case 8:
+ ret = ldq_kernel(T0 & ~7);
+ break;
+ }
+ }
+ } else {
+ switch(size) {
+ case 1:
+ ret = ldub_user(T0);
+ break;
+ case 2:
+ ret = lduw_user(T0 & ~1);
+ break;
+ case 4:
+ ret = ldl_user(T0 & ~3);
+ break;
+ default:
+ case 8:
+ ret = ldq_user(T0 & ~7);
+ break;
+ }
+ }
+ break;
case 0x14: // Bypass
case 0x15: // Bypass, non-cacheable
+ case 0x1c: // Bypass LE
+ case 0x1d: // Bypass, non-cacheable LE
{
switch(size) {
case 1:
}
case 0x04: // Nucleus
case 0x0c: // Nucleus Little Endian (LE)
- case 0x10: // As if user primary
case 0x11: // As if user secondary
- case 0x18: // As if user primary LE
case 0x19: // As if user secondary LE
- case 0x1c: // Bypass LE
- case 0x1d: // Bypass, non-cacheable LE
case 0x24: // Nucleus quad LDD 128 bit atomic
case 0x2c: // Nucleus quad LDD 128 bit atomic
case 0x4a: // UPA config
- case 0x82: // Primary no-fault
+ case 0x81: // Secondary
case 0x83: // Secondary no-fault
- case 0x88: // Primary LE
case 0x89: // Secondary LE
- case 0x8a: // Primary no-fault LE
case 0x8b: // Secondary no-fault LE
// XXX
break;
ret = 0;
break;
}
+
+ /* Convert from little endian */
+ switch (asi) {
+ case 0x0c: // Nucleus Little Endian (LE)
+ case 0x18: // As if user primary LE
+ case 0x19: // As if user secondary LE
+ case 0x1c: // Bypass LE
+ case 0x1d: // Bypass, non-cacheable LE
+ case 0x88: // Primary LE
+ case 0x89: // Secondary LE
+ case 0x8a: // Primary no-fault LE
+ case 0x8b: // Secondary no-fault LE
+ switch(size) {
+ case 2:
+ ret = bswap16(ret);
+ break;
+ case 4:
+ ret = bswap32(ret);
+ break;
+ case 8:
+ ret = bswap64(ret);
+ break;
+ default:
+ break;
+ }
+ default:
+ break;
+ }
+
+ /* Convert to signed number */
+ if (sign) {
+ switch(size) {
+ case 1:
+ ret = (int8_t) ret;
+ break;
+ case 2:
+ ret = (int16_t) ret;
+ break;
+ case 4:
+ ret = (int32_t) ret;
+ break;
+ default:
+ break;
+ }
+ }
T1 = ret;
}
-void helper_st_asi(int asi, int size, int sign)
+void helper_st_asi(int asi, int size)
{
- if (asi < 0x80 && (env->pstate & PS_PRIV) == 0)
+ if ((asi < 0x80 && (env->pstate & PS_PRIV) == 0)
+ || (asi >= 0x30 && asi < 0x80 && !(env->hpstate & HS_PRIV)))
raise_exception(TT_PRIV_ACT);
+ /* Convert to little endian */
+ switch (asi) {
+ case 0x0c: // Nucleus Little Endian (LE)
+ case 0x18: // As if user primary LE
+ case 0x19: // As if user secondary LE
+ case 0x1c: // Bypass LE
+ case 0x1d: // Bypass, non-cacheable LE
+ case 0x88: // Primary LE
+ case 0x89: // Secondary LE
+ switch(size) {
+ case 2:
+ T0 = bswap16(T0);
+ break;
+ case 4:
+ T0 = bswap32(T0);
+ break;
+ case 8:
+ T0 = bswap64(T0);
+ break;
+ default:
+ break;
+ }
+ default:
+ break;
+ }
+
switch(asi) {
+ case 0x10: // As if user primary
+ case 0x18: // As if user primary LE
+ case 0x80: // Primary
+ case 0x88: // Primary LE
+ if ((asi & 0x80) && (env->pstate & PS_PRIV)) {
+ if (env->hpstate & HS_PRIV) {
+ switch(size) {
+ case 1:
+ stb_hypv(T0, T1);
+ break;
+ case 2:
+ stw_hypv(T0 & ~1, T1);
+ break;
+ case 4:
+ stl_hypv(T0 & ~3, T1);
+ break;
+ case 8:
+ default:
+ stq_hypv(T0 & ~7, T1);
+ break;
+ }
+ } else {
+ switch(size) {
+ case 1:
+ stb_kernel(T0, T1);
+ break;
+ case 2:
+ stw_kernel(T0 & ~1, T1);
+ break;
+ case 4:
+ stl_kernel(T0 & ~3, T1);
+ break;
+ case 8:
+ default:
+ stq_kernel(T0 & ~7, T1);
+ break;
+ }
+ }
+ } else {
+ switch(size) {
+ case 1:
+ stb_user(T0, T1);
+ break;
+ case 2:
+ stw_user(T0 & ~1, T1);
+ break;
+ case 4:
+ stl_user(T0 & ~3, T1);
+ break;
+ case 8:
+ default:
+ stq_user(T0 & ~7, T1);
+ break;
+ }
+ }
+ break;
case 0x14: // Bypass
case 0x15: // Bypass, non-cacheable
+ case 0x1c: // Bypass LE
+ case 0x1d: // Bypass, non-cacheable LE
{
switch(size) {
case 1:
return;
case 0x04: // Nucleus
case 0x0c: // Nucleus Little Endian (LE)
- case 0x10: // As if user primary
case 0x11: // As if user secondary
- case 0x18: // As if user primary LE
case 0x19: // As if user secondary LE
- case 0x1c: // Bypass LE
- case 0x1d: // Bypass, non-cacheable LE
case 0x24: // Nucleus quad LDD 128 bit atomic
case 0x2c: // Nucleus quad LDD 128 bit atomic
case 0x4a: // UPA config
- case 0x88: // Primary LE
+ case 0x81: // Secondary
case 0x89: // Secondary LE
// XXX
return;
// Mappings generated during D/I MMU disabled mode are
// invalid in normal mode
if (oldreg != env->lsu) {
+ DPRINTF_MMU("LSU change: 0x%" PRIx64 " -> 0x%" PRIx64 "\n", oldreg, env->lsu);
#ifdef DEBUG_MMU
- printf("LSU change: 0x%" PRIx64 " -> 0x%" PRIx64 "\n", oldreg, env->lsu);
dump_mmu(env);
#endif
tlb_flush(env, 1);
break;
}
env->immuregs[reg] = T1;
-#ifdef DEBUG_MMU
if (oldreg != env->immuregs[reg]) {
- printf("mmu change reg[%d]: 0x%08" PRIx64 " -> 0x%08" PRIx64 "\n", reg, oldreg, env->immuregs[reg]);
+ DPRINTF_MMU("mmu change reg[%d]: 0x%08" PRIx64 " -> 0x%08" PRIx64 "\n", reg, oldreg, env->immuregs[reg]);
}
+#ifdef DEBUG_MMU
dump_mmu(env);
#endif
return;
break;
}
env->dmmuregs[reg] = T1;
-#ifdef DEBUG_MMU
if (oldreg != env->dmmuregs[reg]) {
- printf("mmu change reg[%d]: 0x%08" PRIx64 " -> 0x%08" PRIx64 "\n", reg, oldreg, env->dmmuregs[reg]);
+ DPRINTF_MMU("mmu change reg[%d]: 0x%08" PRIx64 " -> 0x%08" PRIx64 "\n", reg, oldreg, env->dmmuregs[reg]);
}
+#ifdef DEBUG_MMU
dump_mmu(env);
#endif
return;
return;
}
}
-#endif
-#endif /* !CONFIG_USER_ONLY */
+#endif /* CONFIG_USER_ONLY */
+
+void helper_ldf_asi(int asi, int size, int rd)
+{
+ target_ulong tmp_T0 = T0, tmp_T1 = T1;
+ unsigned int i;
+
+ switch (asi) {
+ case 0xf0: // Block load primary
+ case 0xf1: // Block load secondary
+ case 0xf8: // Block load primary LE
+ case 0xf9: // Block load secondary LE
+ if (rd & 7) {
+ raise_exception(TT_ILL_INSN);
+ return;
+ }
+ if (T0 & 0x3f) {
+ raise_exception(TT_UNALIGNED);
+ return;
+ }
+ for (i = 0; i < 16; i++) {
+ helper_ld_asi(asi & 0x8f, 4, 0);
+ *(uint32_t *)&env->fpr[rd++] = T1;
+ T0 += 4;
+ }
+ T0 = tmp_T0;
+ T1 = tmp_T1;
+
+ return;
+ default:
+ break;
+ }
+
+ helper_ld_asi(asi, size, 0);
+ switch(size) {
+ default:
+ case 4:
+ *((uint32_t *)&FT0) = T1;
+ break;
+ case 8:
+ *((int64_t *)&DT0) = T1;
+ break;
+ }
+ T1 = tmp_T1;
+}
+
+void helper_stf_asi(int asi, int size, int rd)
+{
+ target_ulong tmp_T0 = T0, tmp_T1 = T1;
+ unsigned int i;
+
+ switch (asi) {
+ case 0xf0: // Block store primary
+ case 0xf1: // Block store secondary
+ case 0xf8: // Block store primary LE
+ case 0xf9: // Block store secondary LE
+ if (rd & 7) {
+ raise_exception(TT_ILL_INSN);
+ return;
+ }
+ if (T0 & 0x3f) {
+ raise_exception(TT_UNALIGNED);
+ return;
+ }
+ for (i = 0; i < 16; i++) {
+ T1 = *(uint32_t *)&env->fpr[rd++];
+ helper_st_asi(asi & 0x8f, 4);
+ T0 += 4;
+ }
+ T0 = tmp_T0;
+ T1 = tmp_T1;
+
+ return;
+ default:
+ break;
+ }
+
+ switch(size) {
+ default:
+ case 4:
+ T1 = *((uint32_t *)&FT0);
+ break;
+ case 8:
+ T1 = *((int64_t *)&DT0);
+ break;
+ }
+ helper_st_asi(asi, size);
+ T1 = tmp_T1;
+}
+
+#endif /* TARGET_SPARC64 */
#ifndef TARGET_SPARC64
void helper_rett()
void do_popc()
{
- T0 = (T1 & 0x5555555555555555ULL) + ((T1 >> 1) & 0x5555555555555555ULL);
- T0 = (T0 & 0x3333333333333333ULL) + ((T0 >> 2) & 0x3333333333333333ULL);
- T0 = (T0 & 0x0f0f0f0f0f0f0f0fULL) + ((T0 >> 4) & 0x0f0f0f0f0f0f0f0fULL);
- T0 = (T0 & 0x00ff00ff00ff00ffULL) + ((T0 >> 8) & 0x00ff00ff00ff00ffULL);
- T0 = (T0 & 0x0000ffff0000ffffULL) + ((T0 >> 16) & 0x0000ffff0000ffffULL);
- T0 = (T0 & 0x00000000ffffffffULL) + ((T0 >> 32) & 0x00000000ffffffffULL);
+ T0 = ctpop64(T1);
}
static inline uint64_t *get_gregset(uint64_t pstate)
#define MMUSUFFIX _mmu
#define ALIGNED_ONLY
-#define GETPC() (__builtin_return_address(0))
+#ifdef __s390__
+# define GETPC() ((void*)((unsigned long)__builtin_return_address(0) & 0x7fffffffUL))
+#else
+# define GETPC() (__builtin_return_address(0))
+#endif
#define SHIFT 0
#include "softmmu_template.h"
NULL, it means that the function was called in C code (i.e. not
from generated code or from helper.c) */
/* XXX: fix it to restore all registers */
-void tlb_fill(target_ulong addr, int is_write, int is_user, void *retaddr)
+void tlb_fill(target_ulong addr, int is_write, int mmu_idx, void *retaddr)
{
TranslationBlock *tb;
int ret;
saved_env = env;
env = cpu_single_env;
- ret = cpu_sparc_handle_mmu_fault(env, addr, is_write, is_user, 1);
+ ret = cpu_sparc_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
if (ret) {
if (retaddr) {
/* now we have a real cpu fault */
}
#endif
-#ifdef TARGET_SPARC64
-void do_tick_set_count(void *opaque, uint64_t count)
-{
-#if !defined(CONFIG_USER_ONLY)
- ptimer_set_count(opaque, -count);
-#endif
-}
-
-uint64_t do_tick_get_count(void *opaque)
-{
-#if !defined(CONFIG_USER_ONLY)
- return -ptimer_get_count(opaque);
-#else
- return 0;
-#endif
-}
-
-void do_tick_set_limit(void *opaque, uint64_t limit)
-{
-#if !defined(CONFIG_USER_ONLY)
- ptimer_set_limit(opaque, -limit, 0);
-#endif
-}
-#endif