aboutsummaryrefslogtreecommitdiff
path: root/target-sparc/op_helper.c
diff options
context:
space:
mode:
Diffstat (limited to 'target-sparc/op_helper.c')
-rw-r--r--target-sparc/op_helper.c493
1 files changed, 377 insertions, 116 deletions
diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c
index fa51cdee9..b711c6273 100644
--- a/target-sparc/op_helper.c
+++ b/target-sparc/op_helper.c
@@ -1,10 +1,26 @@
#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;
@@ -54,6 +70,38 @@ void do_fitod(void)
{
DT0 = int32_to_float64(*((int32_t *)&FT1), &env->fp_status);
}
+
+#if defined(CONFIG_USER_ONLY)
+void do_fitoq(void)
+{
+ QT0 = int32_to_float128(*((int32_t *)&FT1), &env->fp_status);
+}
+#endif
+
+#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();
+}
+
+#if defined(CONFIG_USER_ONLY)
+void do_fxtoq(void)
+{
+ set_float_exception_flags(0, &env->fp_status);
+ QT0 = int64_to_float128(*((int32_t *)&DT1), &env->fp_status);
+ check_ieee_exceptions();
+}
+#endif
+#endif
#endif
void do_fabss(void)
@@ -66,6 +114,13 @@ void do_fabsd(void)
{
DT0 = float64_abs(DT1);
}
+
+#if defined(CONFIG_USER_ONLY)
+void do_fabsq(void)
+{
+ QT0 = float128_abs(QT1);
+}
+#endif
#endif
void do_fsqrts(void)
@@ -82,6 +137,15 @@ void do_fsqrtd(void)
check_ieee_exceptions();
}
+#if defined(CONFIG_USER_ONLY)
+void do_fsqrtq(void)
+{
+ set_float_exception_flags(0, &env->fp_status);
+ QT0 = float128_sqrt(QT1, &env->fp_status);
+ check_ieee_exceptions();
+}
+#endif
+
#define GEN_FCMP(name, size, reg1, reg2, FS, TRAP) \
void glue(do_, name) (void) \
{ \
@@ -117,6 +181,11 @@ GEN_FCMP(fcmpd, float64, DT0, DT1, 0, 0);
GEN_FCMP(fcmpes, float32, FT0, FT1, 0, 1);
GEN_FCMP(fcmped, float64, DT0, DT1, 0, 1);
+#ifdef CONFIG_USER_ONLY
+GEN_FCMP(fcmpq, float128, QT0, QT1, 0, 0);
+GEN_FCMP(fcmpeq, float128, QT0, QT1, 0, 1);
+#endif
+
#ifdef TARGET_SPARC64
GEN_FCMP(fcmps_fcc1, float32, FT0, FT1, 22, 0);
GEN_FCMP(fcmpd_fcc1, float64, DT0, DT1, 22, 0);
@@ -135,16 +204,79 @@ GEN_FCMP(fcmped_fcc2, float64, DT0, DT1, 24, 1);
GEN_FCMP(fcmpes_fcc3, float32, FT0, FT1, 26, 1);
GEN_FCMP(fcmped_fcc3, float64, DT0, DT1, 26, 1);
+#ifdef CONFIG_USER_ONLY
+GEN_FCMP(fcmpq_fcc1, float128, QT0, QT1, 22, 0);
+GEN_FCMP(fcmpq_fcc2, float128, QT0, QT1, 24, 0);
+GEN_FCMP(fcmpq_fcc3, float128, QT0, QT1, 26, 0);
+GEN_FCMP(fcmpeq_fcc1, float128, QT0, QT1, 22, 1);
+GEN_FCMP(fcmpeq_fcc2, float128, QT0, QT1, 24, 1);
+GEN_FCMP(fcmpeq_fcc3, float128, QT0, QT1, 26, 1);
+#endif
#endif
#ifndef TARGET_SPARC64
#ifndef CONFIG_USER_ONLY
+
+#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]);
+}
+#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] >> 32;
+ T0 = env->mxccregs[3];
+ } 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] >> 32;
+ T0 = env->mxccregs[7];
+ } 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 */
{
@@ -157,21 +289,21 @@ void helper_ld_asi(int asi, int size, int sign)
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 */
{
- int reg = (T0 >> 8) & 0xf;
+ int reg = (T0 >> 8) & 0x1f;
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
+ env->mmuregs[3] = 0;
+ else if (reg == 0x13) /* Fault status read */
+ ret = env->mmuregs[3];
+ else if (reg == 0x14) /* Fault address read */
+ ret = env->mmuregs[4];
+ DPRINTF_MMU("mmu_read: reg[%d] = 0x%08x\n", reg, ret);
}
break;
case 9: /* Supervisor code access */
@@ -187,8 +319,9 @@ void helper_ld_asi(int asi, int size, int sign)
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;
@@ -205,8 +338,9 @@ void helper_ld_asi(int asi, int size, int sign)
ret = ldl_user(T0 & ~3);
break;
case 8:
- ret = ldl_user(T0 & ~3);
- T0 = ldl_user((T0 + 4) & ~3);
+ tmp = ldq_user(T0 & ~7);
+ ret = tmp >> 32;
+ T0 = tmp;
break;
}
break;
@@ -223,8 +357,9 @@ void helper_ld_asi(int asi, int size, int sign)
ret = ldl_kernel(T0 & ~3);
break;
case 8:
- ret = ldl_kernel(T0 & ~3);
- T0 = ldl_kernel((T0 + 4) & ~3);
+ tmp = ldq_kernel(T0 & ~7);
+ ret = tmp >> 32;
+ T0 = tmp;
break;
}
break;
@@ -246,8 +381,9 @@ void helper_ld_asi(int asi, int size, int sign)
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;
@@ -268,13 +404,16 @@ void helper_ld_asi(int asi, int size, int sign)
| ((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;
+ case 0x39: /* data cache diagnostic register */
+ ret = 0;
+ break;
case 0x21 ... 0x2d: /* MMU passthrough, unassigned */
default:
do_unassigned_access(T0, 0, 0, 1);
@@ -302,15 +441,91 @@ 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);
@@ -331,17 +546,18 @@ void helper_st_asi(int asi, int size)
}
case 4: /* write MMU regs */
{
- int reg = (T0 >> 8) & 0xf;
+ int reg = (T0 >> 8) & 0x1f;
uint32_t oldreg;
oldreg = env->mmuregs[reg];
switch(reg) {
case 0:
- env->mmuregs[reg] &= ~(MMU_E | MMU_NF | MMU_BM);
- env->mmuregs[reg] |= T1 & (MMU_E | MMU_NF | MMU_BM);
+ env->mmuregs[reg] = (env->mmuregs[reg] & 0xff000000) |
+ (T1 & 0x00ffffff);
// Mappings generated during no-fault mode or MMU
// disabled mode are invalid in normal mode
- if (oldreg != env->mmuregs[reg])
+ if ((oldreg & (MMU_E | MMU_NF | env->mmu_bm)) !=
+ (env->mmuregs[reg] & (MMU_E | MMU_NF | env->mmu_bm)))
tlb_flush(env, 1);
break;
case 2:
@@ -355,14 +571,20 @@ void helper_st_asi(int asi, int size)
case 3:
case 4:
break;
+ case 0x13:
+ env->mmuregs[3] = T1;
+ break;
+ case 0x14:
+ env->mmuregs[4] = T1;
+ break;
default:
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;
@@ -380,8 +602,7 @@ void helper_st_asi(int asi, int size)
stl_user(T0 & ~3, T1);
break;
case 8:
- stl_user(T0 & ~3, T1);
- stl_user((T0 + 4) & ~3, T2);
+ stq_user(T0 & ~7, ((uint64_t)T1 << 32) | T2);
break;
}
break;
@@ -398,8 +619,7 @@ void helper_st_asi(int asi, int size)
stl_kernel(T0 & ~3, T1);
break;
case 8:
- stl_kernel(T0 & ~3, T1);
- stl_kernel((T0 + 4) & ~3, T2);
+ stq_kernel(T0 & ~7, ((uint64_t)T1 << 32) | T2);
break;
}
break;
@@ -456,8 +676,7 @@ void helper_st_asi(int asi, int size)
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;
}
}
@@ -480,17 +699,20 @@ void helper_st_asi(int asi, int size)
| ((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;
}
}
return;
- case 0x31: /* Ross RT620 I-cache flush */
+ case 0x30: /* store buffer tags */
+ case 0x31: /* store buffer data or Ross RT620 I-cache flush */
+ case 0x32: /* store buffer control */
case 0x36: /* I-cache flash clear */
case 0x37: /* D-cache flash clear */
+ case 0x38: /* breakpoint diagnostics */
+ case 0x4c: /* breakpoint action */
break;
case 9: /* Supervisor code access, XXX */
case 0x21 ... 0x2d: /* MMU passthrough, unassigned */
@@ -654,7 +876,8 @@ 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 && (env->pstate & PS_PRIV) == 0)
+ || (asi >= 0x30 && asi < 0x80 && !(env->hpstate & HS_PRIV)))
raise_exception(TT_PRIV_ACT);
switch (asi) {
@@ -665,20 +888,38 @@ void helper_ld_asi(int asi, int size, int sign)
case 0x88: // Primary LE
case 0x8a: // Primary no-fault LE
if ((asi & 0x80) && (env->pstate & PS_PRIV)) {
- 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;
+ 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) {
@@ -852,7 +1093,8 @@ void helper_ld_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 */
@@ -862,7 +1104,6 @@ void helper_st_asi(int asi, int size)
case 0x19: // As if user secondary LE
case 0x1c: // Bypass LE
case 0x1d: // Bypass, non-cacheable LE
- case 0x81: // Secondary
case 0x88: // Primary LE
case 0x89: // Secondary LE
switch(size) {
@@ -888,20 +1129,38 @@ void helper_st_asi(int asi, int size)
case 0x80: // Primary
case 0x88: // Primary LE
if ((asi & 0x80) && (env->pstate & PS_PRIV)) {
- 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;
+ 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) {
@@ -950,6 +1209,7 @@ void helper_st_asi(int asi, int size)
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
// XXX
return;
@@ -962,8 +1222,8 @@ void helper_st_asi(int asi, int size)
// 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);
@@ -995,10 +1255,10 @@ void helper_st_asi(int asi, int size)
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;
@@ -1064,10 +1324,10 @@ void helper_st_asi(int asi, int size)
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;
@@ -1137,10 +1397,18 @@ void helper_ldf_asi(int asi, int size, int rd)
case 0xf1: // Block load secondary
case 0xf8: // Block load primary LE
case 0xf9: // Block load secondary LE
- for (i = 0; i < 8; i++) {
- helper_ld_asi(asi & 0x8f, 8, 0);
- *((int64_t *)&DT0) = T1;
- T0 += 8;
+ 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;
@@ -1159,6 +1427,11 @@ void helper_ldf_asi(int asi, int size, int rd)
case 8:
*((int64_t *)&DT0) = T1;
break;
+#if defined(CONFIG_USER_ONLY)
+ case 16:
+ // XXX
+ break;
+#endif
}
T1 = tmp_T1;
}
@@ -1173,10 +1446,18 @@ void helper_stf_asi(int asi, int size, int rd)
case 0xf1: // Block store secondary
case 0xf8: // Block store primary LE
case 0xf9: // Block store secondary LE
- for (i = 0; i < 8; i++) {
- T1 = *((int64_t *)&DT0);
- helper_st_asi(asi & 0x8f, 8);
- T0 += 8;
+ 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;
@@ -1194,6 +1475,11 @@ void helper_stf_asi(int asi, int size, int rd)
case 8:
T1 = *((int64_t *)&DT0);
break;
+#if defined(CONFIG_USER_ONLY)
+ case 16:
+ // XXX
+ break;
+#endif
}
helper_st_asi(asi, size);
T1 = tmp_T1;
@@ -1264,12 +1550,7 @@ void do_rdpsr()
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)
@@ -1479,7 +1760,11 @@ static void do_unaligned_access(target_ulong addr, int is_write, int is_user,
#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"
@@ -1506,7 +1791,7 @@ static void do_unaligned_access(target_ulong addr, int is_write, int is_user,
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;
@@ -1518,7 +1803,7 @@ void tlb_fill(target_ulong addr, int is_write, int is_user, void *retaddr)
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 */
@@ -1593,27 +1878,3 @@ void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec,
}
#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