]> git.proxmox.com Git - qemu.git/blobdiff - target-sparc/op_helper.c
sparc: fix coding style of the area to be moved
[qemu.git] / target-sparc / op_helper.c
index 6deebd35d2c6dc44e6e60e9d5d00a7ba5ad464c3..f049e380bd6c8cc0e00f1ee9695d976521f9480a 100644 (file)
@@ -1,6 +1,7 @@
 #include "exec.h"
 #include "host-utils.h"
 #include "helper.h"
+#include "sysemu.h"
 
 //#define DEBUG_MMU
 //#define DEBUG_MXCC
@@ -9,6 +10,7 @@
 //#define DEBUG_ASI
 //#define DEBUG_PCALL
 //#define DEBUG_PSTATE
+//#define DEBUG_CACHE_CONTROL
 
 #ifdef DEBUG_MMU
 #define DPRINTF_MMU(fmt, ...)                                   \
 #define DPRINTF_PSTATE(fmt, ...) do {} while (0)
 #endif
 
+#ifdef DEBUG_CACHE_CONTROL
+#define DPRINTF_CACHE_CONTROL(fmt, ...)                                   \
+    do { printf("CACHE_CONTROL: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF_CACHE_CONTROL(fmt, ...) do {} while (0)
+#endif
+
 #ifdef TARGET_SPARC64
 #ifndef TARGET_ABI32
 #define AM_CHECK(env1) ((env1)->pstate & PS_AM)
 #define QT0 (env->qt0)
 #define QT1 (env->qt1)
 
+/* Leon3 cache control */
+
+/* Cache control: emulate the behavior of cache control registers but without
+   any effect on the emulated */
+
+#define CACHE_STATE_MASK 0x3
+#define CACHE_DISABLED   0x0
+#define CACHE_FROZEN     0x1
+#define CACHE_ENABLED    0x3
+
+/* Cache Control register fields */
+
+#define CACHE_CTRL_IF (1 <<  4)  /* Instruction Cache Freeze on Interrupt */
+#define CACHE_CTRL_DF (1 <<  5)  /* Data Cache Freeze on Interrupt */
+#define CACHE_CTRL_DP (1 << 14)  /* Data cache flush pending */
+#define CACHE_CTRL_IP (1 << 15)  /* Instruction cache flush pending */
+#define CACHE_CTRL_IB (1 << 16)  /* Instruction burst fetch */
+#define CACHE_CTRL_FI (1 << 21)  /* Flush Instruction cache (Write only) */
+#define CACHE_CTRL_FD (1 << 22)  /* Flush Data cache (Write only) */
+#define CACHE_CTRL_DS (1 << 23)  /* Data cache snoop enable */
+
 #if defined(CONFIG_USER_ONLY) && defined(TARGET_SPARC64)
 static void do_unassigned_access(target_ulong addr, int is_write, int is_exec,
                           int is_asi, int size);
@@ -180,7 +210,7 @@ static void demap_tlb(SparcTLBEntry *tlb, target_ulong demap_addr,
             replace_tlb_entry(&tlb[i], 0, 0, env1);
 #ifdef DEBUG_MMU
             DPRINTF_MMU("%s demap invalidated entry [%02u]\n", strmmu, i);
-            dump_mmu(env1);
+            dump_mmu(stdout, fprintf, env1);
 #endif
         }
     }
@@ -198,7 +228,7 @@ static void replace_tlb_1bit_lru(SparcTLBEntry *tlb,
             replace_tlb_entry(&tlb[i], tlb_tag, tlb_tte, env1);
 #ifdef DEBUG_MMU
             DPRINTF_MMU("%s lru replaced invalid entry [%i]\n", strmmu, i);
-            dump_mmu(env1);
+            dump_mmu(stdout, fprintf, env1);
 #endif
             return;
         }
@@ -217,7 +247,7 @@ static void replace_tlb_1bit_lru(SparcTLBEntry *tlb,
 #ifdef DEBUG_MMU
                 DPRINTF_MMU("%s lru replaced unlocked %s entry [%i]\n",
                             strmmu, (replace_used?"used":"unused"), i);
-                dump_mmu(env1);
+                dump_mmu(stdout, fprintf, env1);
 #endif
                 return;
             }
@@ -247,10 +277,46 @@ static inline target_ulong address_mask(CPUState *env1, target_ulong addr)
     return addr;
 }
 
+/* returns true if access using this ASI is to have address translated by MMU
+   otherwise access is to raw physical address */
+static inline int is_translating_asi(int asi)
+{
+#ifdef TARGET_SPARC64
+    /* Ultrasparc IIi translating asi
+       - note this list is defined by cpu implementation
+     */
+    switch (asi) {
+    case 0x04 ... 0x11:
+    case 0x18 ... 0x19:
+    case 0x24 ... 0x2C:
+    case 0x70 ... 0x73:
+    case 0x78 ... 0x79:
+    case 0x80 ... 0xFF:
+        return 1;
+
+    default:
+        return 0;
+    }
+#else
+    /* TODO: check sparc32 bits */
+    return 0;
+#endif
+}
+
+static inline target_ulong asi_address_mask(CPUState *env1,
+                                            int asi, target_ulong addr)
+{
+    if (is_translating_asi(asi)) {
+        return address_mask(env, addr);
+    } else {
+        return addr;
+    }
+}
+
 static void raise_exception(int tt)
 {
     env->exception_index = tt;
-    cpu_loop_exit();
+    cpu_loop_exit(env);
 }
 
 void HELPER(raise_exception)(int tt)
@@ -258,6 +324,13 @@ void HELPER(raise_exception)(int tt)
     raise_exception(tt);
 }
 
+void helper_shutdown(void)
+{
+#if !defined(CONFIG_USER_ONLY)
+    qemu_system_shutdown_request();
+#endif
+}
+
 void helper_check_align(target_ulong addr, uint32_t align)
 {
     if (addr & align) {
@@ -821,65 +894,77 @@ void helper_fsqrtq(void)
     QT0 = float128_sqrt(QT1, &env->fp_status);
 }
 
-#define GEN_FCMP(name, size, reg1, reg2, FS, TRAP)                      \
+#define GEN_FCMP(name, size, reg1, reg2, FS, E)                         \
     void glue(helper_, name) (void)                                     \
     {                                                                   \
-        target_ulong new_fsr;                                           \
-                                                                        \
-        env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);                     \
+        env->fsr &= FSR_FTT_NMASK;                                      \
+        if (E && (glue(size, _is_any_nan)(reg1) ||                      \
+                     glue(size, _is_any_nan)(reg2)) &&                  \
+            (env->fsr & FSR_NVM)) {                                     \
+            env->fsr |= FSR_NVC;                                        \
+            env->fsr |= FSR_FTT_IEEE_EXCP;                              \
+            raise_exception(TT_FP_EXCP);                                \
+        }                                                               \
         switch (glue(size, _compare) (reg1, reg2, &env->fp_status)) {   \
         case float_relation_unordered:                                  \
-            new_fsr = (FSR_FCC1 | FSR_FCC0) << FS;                      \
-            if ((env->fsr & FSR_NVM) || TRAP) {                         \
-                env->fsr |= new_fsr;                                    \
+            if ((env->fsr & FSR_NVM)) {                                 \
                 env->fsr |= FSR_NVC;                                    \
                 env->fsr |= FSR_FTT_IEEE_EXCP;                          \
                 raise_exception(TT_FP_EXCP);                            \
             } else {                                                    \
+                env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);             \
+                env->fsr |= (FSR_FCC1 | FSR_FCC0) << FS;                \
                 env->fsr |= FSR_NVA;                                    \
             }                                                           \
             break;                                                      \
         case float_relation_less:                                       \
-            new_fsr = FSR_FCC0 << FS;                                   \
+            env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);                 \
+            env->fsr |= FSR_FCC0 << FS;                                 \
             break;                                                      \
         case float_relation_greater:                                    \
-            new_fsr = FSR_FCC1 << FS;                                   \
+            env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);                 \
+            env->fsr |= FSR_FCC1 << FS;                                 \
             break;                                                      \
         default:                                                        \
-            new_fsr = 0;                                                \
+            env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);                 \
             break;                                                      \
         }                                                               \
-        env->fsr |= new_fsr;                                            \
     }
-#define GEN_FCMPS(name, size, FS, TRAP)                                 \
+#define GEN_FCMPS(name, size, FS, E)                                    \
     void glue(helper_, name)(float32 src1, float32 src2)                \
     {                                                                   \
-        target_ulong new_fsr;                                           \
-                                                                        \
-        env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);                     \
+        env->fsr &= FSR_FTT_NMASK;                                      \
+        if (E && (glue(size, _is_any_nan)(src1) ||                      \
+                     glue(size, _is_any_nan)(src2)) &&                  \
+            (env->fsr & FSR_NVM)) {                                     \
+            env->fsr |= FSR_NVC;                                        \
+            env->fsr |= FSR_FTT_IEEE_EXCP;                              \
+            raise_exception(TT_FP_EXCP);                                \
+        }                                                               \
         switch (glue(size, _compare) (src1, src2, &env->fp_status)) {   \
         case float_relation_unordered:                                  \
-            new_fsr = (FSR_FCC1 | FSR_FCC0) << FS;                      \
-            if ((env->fsr & FSR_NVM) || TRAP) {                         \
-                env->fsr |= new_fsr;                                    \
+            if ((env->fsr & FSR_NVM)) {                                 \
                 env->fsr |= FSR_NVC;                                    \
                 env->fsr |= FSR_FTT_IEEE_EXCP;                          \
                 raise_exception(TT_FP_EXCP);                            \
             } else {                                                    \
+                env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);             \
+                env->fsr |= (FSR_FCC1 | FSR_FCC0) << FS;                \
                 env->fsr |= FSR_NVA;                                    \
             }                                                           \
             break;                                                      \
         case float_relation_less:                                       \
-            new_fsr = FSR_FCC0 << FS;                                   \
+            env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);                 \
+            env->fsr |= FSR_FCC0 << FS;                                 \
             break;                                                      \
         case float_relation_greater:                                    \
-            new_fsr = FSR_FCC1 << FS;                                   \
+            env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);                 \
+            env->fsr |= FSR_FCC1 << FS;                                 \
             break;                                                      \
         default:                                                        \
-            new_fsr = 0;                                                \
+            env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);                 \
             break;                                                      \
         }                                                               \
-        env->fsr |= new_fsr;                                            \
     }
 
 GEN_FCMPS(fcmps, float32, 0, 0);
@@ -1347,7 +1432,7 @@ void helper_compute_psr(void)
     CC_OP = CC_OP_FLAGS;
 }
 
-target_ulong helper_compute_C_icc(void)
+uint32_t helper_compute_C_icc(void)
 {
     uint32_t ret;
 
@@ -1404,11 +1489,7 @@ static target_ulong get_psr(void)
         (env->psrps? PSR_PS : 0) |
         (env->psret? PSR_ET : 0) | env->cwp;
 #else
-    return env->version | (env->psr & PSR_ICC) |
-        (env->psref? PSR_EF : 0) |
-        (env->psrpil << 8) |
-        (env->psrs? PSR_S : 0) |
-        (env->psrps? PSR_PS : 0) | env->cwp;
+    return env->psr & PSR_ICC;
 #endif
 }
 
@@ -1427,17 +1508,19 @@ target_ulong cpu_get_psr(CPUState *env1)
 static void put_psr(target_ulong val)
 {
     env->psr = val & PSR_ICC;
+#if !defined (TARGET_SPARC64)
     env->psref = (val & PSR_EF)? 1 : 0;
     env->psrpil = (val & PSR_PIL) >> 8;
+#endif
 #if ((!defined (TARGET_SPARC64)) && !defined(CONFIG_USER_ONLY))
     cpu_check_irqs(env);
 #endif
+#if !defined (TARGET_SPARC64)
     env->psrs = (val & PSR_S)? 1 : 0;
     env->psrps = (val & PSR_PS)? 1 : 0;
-#if !defined (TARGET_SPARC64)
     env->psret = (val & PSR_ET)? 1 : 0;
-#endif
     set_cwp(val & PSR_CWP);
+#endif
     env->cc_op = CC_OP_FLAGS;
 }
 
@@ -1566,6 +1649,109 @@ static void dump_asi(const char *txt, target_ulong addr, int asi, int size,
 
 #ifndef TARGET_SPARC64
 #ifndef CONFIG_USER_ONLY
+
+
+/* Leon3 cache control */
+
+static void leon3_cache_control_int(void)
+{
+    uint32_t state = 0;
+
+    if (env->cache_control & CACHE_CTRL_IF) {
+        /* Instruction cache state */
+        state = env->cache_control & CACHE_STATE_MASK;
+        if (state == CACHE_ENABLED) {
+            state = CACHE_FROZEN;
+            DPRINTF_CACHE_CONTROL("Instruction cache: freeze\n");
+        }
+
+        env->cache_control &= ~CACHE_STATE_MASK;
+        env->cache_control |= state;
+    }
+
+    if (env->cache_control & CACHE_CTRL_DF) {
+        /* Data cache state */
+        state = (env->cache_control >> 2) & CACHE_STATE_MASK;
+        if (state == CACHE_ENABLED) {
+            state = CACHE_FROZEN;
+            DPRINTF_CACHE_CONTROL("Data cache: freeze\n");
+        }
+
+        env->cache_control &= ~(CACHE_STATE_MASK << 2);
+        env->cache_control |= (state << 2);
+    }
+}
+
+static void leon3_cache_control_st(target_ulong addr, uint64_t val, int size)
+{
+    DPRINTF_CACHE_CONTROL("st addr:%08x, val:%" PRIx64 ", size:%d\n",
+                          addr, val, size);
+
+    if (size != 4) {
+        DPRINTF_CACHE_CONTROL("32bits only\n");
+        return;
+    }
+
+    switch (addr) {
+    case 0x00:              /* Cache control */
+
+        /* These values must always be read as zeros */
+        val &= ~CACHE_CTRL_FD;
+        val &= ~CACHE_CTRL_FI;
+        val &= ~CACHE_CTRL_IB;
+        val &= ~CACHE_CTRL_IP;
+        val &= ~CACHE_CTRL_DP;
+
+        env->cache_control = val;
+        break;
+    case 0x04:              /* Instruction cache configuration */
+    case 0x08:              /* Data cache configuration */
+        /* Read Only */
+        break;
+    default:
+        DPRINTF_CACHE_CONTROL("write unknown register %08x\n", addr);
+        break;
+    };
+}
+
+static uint64_t leon3_cache_control_ld(target_ulong addr, int size)
+{
+    uint64_t ret = 0;
+
+    if (size != 4) {
+        DPRINTF_CACHE_CONTROL("32bits only\n");
+        return 0;
+    }
+
+    switch (addr) {
+    case 0x00:              /* Cache control */
+        ret = env->cache_control;
+        break;
+
+        /* Configuration registers are read and only always keep those
+           predefined values */
+
+    case 0x04:              /* Instruction cache configuration */
+        ret = 0x10220000;
+        break;
+    case 0x08:              /* Data cache configuration */
+        ret = 0x18220000;
+        break;
+    default:
+        DPRINTF_CACHE_CONTROL("read unknown register %08x\n", addr);
+        break;
+    };
+    DPRINTF_CACHE_CONTROL("ld addr:%08x, ret:0x%" PRIx64 ", size:%d\n",
+                          addr, ret, size);
+    return ret;
+}
+
+void leon3_irq_manager(void *irq_manager, int intno)
+{
+    leon3_irq_ack(irq_manager, intno);
+    leon3_cache_control_int();
+}
+
 uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
 {
     uint64_t ret = 0;
@@ -1575,8 +1761,15 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
 
     helper_check_align(addr, size - 1);
     switch (asi) {
-    case 2: /* SuperSparc MXCC registers */
+    case 2: /* SuperSparc MXCC registers and Leon3 cache control */
         switch (addr) {
+        case 0x00:          /* Leon3 Cache Control */
+        case 0x08:          /* Leon3 Instruction Cache config */
+        case 0x0C:          /* Leon3 Date Cache config */
+            if (env->def->features & CPU_FEATURE_CACHE_CTRL) {
+                ret = leon3_cache_control_ld(addr, size);
+            }
+            break;
         case 0x01c00a00: /* MXCC control register */
             if (size == 8)
                 ret = env->mxccregs[3];
@@ -1772,6 +1965,18 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
                         ret);
         }
         break;
+    case 0x49: /* SuperSPARC MMU Counter Breakpoint Value */
+        ret = env->mmubpctrv;
+        break;
+    case 0x4a: /* SuperSPARC MMU Counter Breakpoint Control */
+        ret = env->mmubpctrc;
+        break;
+    case 0x4b: /* SuperSPARC MMU Counter Breakpoint Status */
+        ret = env->mmubpctrs;
+        break;
+    case 0x4c: /* SuperSPARC MMU Breakpoint Action */
+        ret = env->mmubpaction;
+        break;
     case 8: /* User code access, XXX */
     default:
         do_unassigned_access(addr, 0, 0, asi, size);
@@ -1803,8 +2008,16 @@ void helper_st_asi(target_ulong addr, uint64_t val, int asi, int size)
 {
     helper_check_align(addr, size - 1);
     switch(asi) {
-    case 2: /* SuperSparc MXCC registers */
+    case 2: /* SuperSparc MXCC registers and Leon3 cache control */
         switch (addr) {
+        case 0x00:          /* Leon3 Cache Control */
+        case 0x08:          /* Leon3 Instruction Cache config */
+        case 0x0C:          /* Leon3 Date Cache config */
+            if (env->def->features & CPU_FEATURE_CACHE_CTRL) {
+                leon3_cache_control_st(addr, val, size);
+            }
+            break;
+
         case 0x01c00000: /* MXCC stream data register 0 */
             if (size == 8)
                 env->mxccdata[0] = val;
@@ -1924,7 +2137,7 @@ void helper_st_asi(target_ulong addr, uint64_t val, int asi, int size)
                 break;
             }
 #ifdef DEBUG_MMU
-            dump_mmu(env);
+            dump_mmu(stdout, fprintf, env);
 #endif
         }
         break;
@@ -1976,7 +2189,7 @@ void helper_st_asi(target_ulong addr, uint64_t val, int asi, int size)
                             reg, oldreg, env->mmuregs[reg]);
             }
 #ifdef DEBUG_MMU
-            dump_mmu(env);
+            dump_mmu(stdout, fprintf, env);
 #endif
         }
         break;
@@ -2102,7 +2315,6 @@ void helper_st_asi(target_ulong addr, uint64_t val, int asi, int size)
                // descriptor diagnostic
     case 0x36: /* I-cache flash clear */
     case 0x37: /* D-cache flash clear */
-    case 0x4c: /* breakpoint action */
         break;
     case 0x38: /* SuperSPARC MMU Breakpoint Control Registers*/
         {
@@ -2126,6 +2338,18 @@ void helper_st_asi(target_ulong addr, uint64_t val, int asi, int size)
                         env->mmuregs[reg]);
         }
         break;
+    case 0x49: /* SuperSPARC MMU Counter Breakpoint Value */
+        env->mmubpctrv = val & 0xffffffff;
+        break;
+    case 0x4a: /* SuperSPARC MMU Counter Breakpoint Control */
+        env->mmubpctrc = val & 0x3;
+        break;
+    case 0x4b: /* SuperSPARC MMU Counter Breakpoint Status */
+        env->mmubpctrs = val & 0x3;
+        break;
+    case 0x4c: /* SuperSPARC MMU Breakpoint Action */
+        env->mmubpaction = val & 0x1fff;
+        break;
     case 8: /* User code access, XXX */
     case 9: /* Supervisor code access, XXX */
     default:
@@ -2152,7 +2376,7 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
         raise_exception(TT_PRIV_ACT);
 
     helper_check_align(addr, size - 1);
-    addr = address_mask(env, addr);
+    addr = asi_address_mask(env, asi, addr);
 
     switch (asi) {
     case 0x82: // Primary no-fault
@@ -2255,7 +2479,7 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
         raise_exception(TT_PRIV_ACT);
 
     helper_check_align(addr, size - 1);
-    addr = address_mask(env, addr);
+    addr = asi_address_mask(env, asi, addr);
 
     /* Convert to little endian */
     switch (asi) {
@@ -2326,12 +2550,14 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
     asi &= 0xff;
 
     if ((asi < 0x80 && (env->pstate & PS_PRIV) == 0)
-        || ((env->def->features & CPU_FEATURE_HYPV)
+        || (cpu_has_hypervisor(env)
             && asi >= 0x30 && asi < 0x80
             && !(env->hpstate & HS_PRIV)))
         raise_exception(TT_PRIV_ACT);
 
     helper_check_align(addr, size - 1);
+    addr = asi_address_mask(env, asi, addr);
+
     switch (asi) {
     case 0x82: // Primary no-fault
     case 0x8a: // Primary no-fault LE
@@ -2361,8 +2587,7 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
     case 0xe2: // UA2007 Primary block init
     case 0xe3: // UA2007 Secondary block init
         if ((asi & 0x80) && (env->pstate & PS_PRIV)) {
-            if ((env->def->features & CPU_FEATURE_HYPV)
-                && env->hpstate & HS_PRIV) {
+            if (cpu_hypervisor_mode(env)) {
                 switch(size) {
                 case 1:
                     ret = ldub_hypv(addr);
@@ -2678,12 +2903,14 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
     asi &= 0xff;
 
     if ((asi < 0x80 && (env->pstate & PS_PRIV) == 0)
-        || ((env->def->features & CPU_FEATURE_HYPV)
+        || (cpu_has_hypervisor(env)
             && asi >= 0x30 && asi < 0x80
             && !(env->hpstate & HS_PRIV)))
         raise_exception(TT_PRIV_ACT);
 
     helper_check_align(addr, size - 1);
+    addr = asi_address_mask(env, asi, addr);
+
     /* Convert to little endian */
     switch (asi) {
     case 0x0c: // Nucleus Little Endian (LE)
@@ -2722,8 +2949,7 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
     case 0xe2: // UA2007 Primary block init
     case 0xe3: // UA2007 Secondary block init
         if ((asi & 0x80) && (env->pstate & PS_PRIV)) {
-            if ((env->def->features & CPU_FEATURE_HYPV)
-                && env->hpstate & HS_PRIV) {
+            if (cpu_hypervisor_mode(env)) {
                 switch(size) {
                 case 1:
                     stb_hypv(addr, val);
@@ -2875,7 +3101,7 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
                 DPRINTF_MMU("LSU change: 0x%" PRIx64 " -> 0x%" PRIx64 "\n",
                             oldreg, env->lsu);
 #ifdef DEBUG_MMU
-                dump_mmu(env);
+                dump_mmu(stdout, fprintf, env1);
 #endif
                 tlb_flush(env, 1);
             }
@@ -2920,7 +3146,7 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
                             PRIx64 "\n", reg, oldreg, env->immuregs[reg]);
             }
 #ifdef DEBUG_MMU
-            dump_mmu(env);
+            dump_mmu(stdout, fprintf, env);
 #endif
             return;
         }
@@ -2937,7 +3163,7 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
 
 #ifdef DEBUG_MMU
             DPRINTF_MMU("immu data access replaced entry [%i]\n", i);
-            dump_mmu(env);
+            dump_mmu(stdout, fprintf, env);
 #endif
             return;
         }
@@ -2963,9 +3189,15 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
                 break;
             case 1: // Primary context
                 env->dmmu.mmu_primary_context = val;
+                /* can be optimized to only flush MMU_USER_IDX
+                   and MMU_KERNEL_IDX entries */
+                tlb_flush(env, 1);
                 break;
             case 2: // Secondary context
                 env->dmmu.mmu_secondary_context = val;
+                /* can be optimized to only flush MMU_USER_SECONDARY_IDX
+                   and MMU_KERNEL_SECONDARY_IDX entries */
+                tlb_flush(env, 1);
                 break;
             case 5: // TSB access
                 DPRINTF_MMU("dmmu TSB write: 0x%016" PRIx64 " -> 0x%016"
@@ -2987,7 +3219,7 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
                             PRIx64 "\n", reg, oldreg, env->dmmuregs[reg]);
             }
 #ifdef DEBUG_MMU
-            dump_mmu(env);
+            dump_mmu(stdout, fprintf, env);
 #endif
             return;
         }
@@ -3002,7 +3234,7 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
 
 #ifdef DEBUG_MMU
             DPRINTF_MMU("dmmu data access replaced entry [%i]\n", i);
-            dump_mmu(env);
+            dump_mmu(stdout, fprintf, env);
 #endif
             return;
         }
@@ -3048,35 +3280,39 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
 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)
+        || (cpu_has_hypervisor(env)
             && asi >= 0x30 && asi < 0x80
             && !(env->hpstate & HS_PRIV)))
         raise_exception(TT_PRIV_ACT);
 
+    addr = asi_address_mask(env, asi, addr);
+
     switch (asi) {
+#if !defined(CONFIG_USER_ONLY)
     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);
+            env->gregs[1] = ldq_nucleus(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);
+            env->gregs[rd] = ldq_nucleus(addr);
+            env->gregs[rd + 1] = ldq_nucleus(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);
+            env->regwptr[rd] = ldq_nucleus(addr);
+            env->regwptr[rd + 1] = ldq_nucleus(addr + 8);
             if (asi == 0x2c) {
                 bswap64s(&env->regwptr[rd]);
                 bswap64s(&env->regwptr[rd + 1]);
             }
         }
         break;
+#endif
     default:
         helper_check_align(addr, 0x3);
         if (rd == 0)
@@ -3098,6 +3334,8 @@ void helper_ldf_asi(target_ulong addr, int asi, int size, int rd)
     target_ulong val;
 
     helper_check_align(addr, 3);
+    addr = asi_address_mask(env, asi, addr);
+
     switch (asi) {
     case 0xf0: // Block load primary
     case 0xf1: // Block load secondary
@@ -3114,6 +3352,20 @@ void helper_ldf_asi(target_ulong addr, int asi, int size, int rd)
             addr += 4;
         }
 
+        return;
+    case 0x70: // Block load primary, user privilege
+    case 0x71: // Block load secondary, user privilege
+        if (rd & 7) {
+            raise_exception(TT_ILL_INSN);
+            return;
+        }
+        helper_check_align(addr, 0x3f);
+        for (i = 0; i < 16; i++) {
+            *(uint32_t *)&env->fpr[rd++] = helper_ld_asi(addr, asi & 0x1f, 4,
+                                                         0);
+            addr += 4;
+        }
+
         return;
     default:
         break;
@@ -3140,6 +3392,8 @@ void helper_stf_asi(target_ulong addr, int asi, int size, int rd)
     target_ulong val = 0;
 
     helper_check_align(addr, 3);
+    addr = asi_address_mask(env, asi, addr);
+
     switch (asi) {
     case 0xe0: // UA2007 Block commit store primary (cache flush)
     case 0xe1: // UA2007 Block commit store secondary (cache flush)
@@ -3158,6 +3412,20 @@ void helper_stf_asi(target_ulong addr, int asi, int size, int rd)
             addr += 4;
         }
 
+        return;
+    case 0x70: // Block store primary, user privilege
+    case 0x71: // Block store secondary, user privilege
+        if (rd & 7) {
+            raise_exception(TT_ILL_INSN);
+            return;
+        }
+        helper_check_align(addr, 0x3f);
+        for (i = 0; i < 16; i++) {
+            val = *(uint32_t *)&env->fpr[rd++];
+            helper_st_asi(addr, val, asi & 0x1f, 4);
+            addr += 4;
+        }
+
         return;
     default:
         break;
@@ -3221,13 +3489,14 @@ void helper_rett(void)
 }
 #endif
 
-target_ulong helper_udiv(target_ulong a, target_ulong b)
+static target_ulong helper_udiv_common(target_ulong a, target_ulong b, int cc)
 {
+    int overflow = 0;
     uint64_t x0;
     uint32_t x1;
 
     x0 = (a & 0xffffffff) | ((int64_t) (env->y) << 32);
-    x1 = b;
+    x1 = (b & 0xffffffff);
 
     if (x1 == 0) {
         raise_exception(TT_DIV_ZERO);
@@ -3235,21 +3504,36 @@ target_ulong helper_udiv(target_ulong a, target_ulong b)
 
     x0 = x0 / x1;
     if (x0 > 0xffffffff) {
-        env->cc_src2 = 1;
-        return 0xffffffff;
-    } else {
-        env->cc_src2 = 0;
-        return x0;
+        x0 = 0xffffffff;
+        overflow = 1;
     }
+
+    if (cc) {
+        env->cc_dst = x0;
+        env->cc_src2 = overflow;
+        env->cc_op = CC_OP_DIV;
+    }
+    return x0;
 }
 
-target_ulong helper_sdiv(target_ulong a, target_ulong b)
+target_ulong helper_udiv(target_ulong a, target_ulong b)
 {
+    return helper_udiv_common(a, b, 0);
+}
+
+target_ulong helper_udiv_cc(target_ulong a, target_ulong b)
+{
+    return helper_udiv_common(a, b, 1);
+}
+
+static target_ulong helper_sdiv_common(target_ulong a, target_ulong b, int cc)
+{
+    int overflow = 0;
     int64_t x0;
     int32_t x1;
 
     x0 = (a & 0xffffffff) | ((int64_t) (env->y) << 32);
-    x1 = b;
+    x1 = (b & 0xffffffff);
 
     if (x1 == 0) {
         raise_exception(TT_DIV_ZERO);
@@ -3257,12 +3541,26 @@ target_ulong helper_sdiv(target_ulong a, target_ulong b)
 
     x0 = x0 / x1;
     if ((int32_t) x0 != x0) {
-        env->cc_src2 = 1;
-        return x0 < 0? 0x80000000: 0x7fffffff;
-    } else {
-        env->cc_src2 = 0;
-        return x0;
+        x0 = x0 < 0 ? 0x80000000: 0x7fffffff;
+        overflow = 1;
     }
+
+    if (cc) {
+        env->cc_dst = x0;
+        env->cc_src2 = overflow;
+        env->cc_op = CC_OP_DIV;
+    }
+    return x0;
+}
+
+target_ulong helper_sdiv(target_ulong a, target_ulong b)
+{
+    return helper_sdiv_common(a, b, 0);
+}
+
+target_ulong helper_sdiv_cc(target_ulong a, target_ulong b)
+{
+    return helper_sdiv_common(a, b, 1);
 }
 
 void helper_stdf(target_ulong addr, int mem_idx)
@@ -3270,18 +3568,19 @@ void helper_stdf(target_ulong addr, int mem_idx)
     helper_check_align(addr, 7);
 #if !defined(CONFIG_USER_ONLY)
     switch (mem_idx) {
-    case 0:
+    case MMU_USER_IDX:
         stfq_user(addr, DT0);
         break;
-    case 1:
+    case MMU_KERNEL_IDX:
         stfq_kernel(addr, DT0);
         break;
 #ifdef TARGET_SPARC64
-    case 2:
+    case MMU_HYPV_IDX:
         stfq_hypv(addr, DT0);
         break;
 #endif
     default:
+        DPRINTF_MMU("helper_stdf: need to check MMU idx %d\n", mem_idx);
         break;
     }
 #else
@@ -3294,18 +3593,19 @@ void helper_lddf(target_ulong addr, int mem_idx)
     helper_check_align(addr, 7);
 #if !defined(CONFIG_USER_ONLY)
     switch (mem_idx) {
-    case 0:
+    case MMU_USER_IDX:
         DT0 = ldfq_user(addr);
         break;
-    case 1:
+    case MMU_KERNEL_IDX:
         DT0 = ldfq_kernel(addr);
         break;
 #ifdef TARGET_SPARC64
-    case 2:
+    case MMU_HYPV_IDX:
         DT0 = ldfq_hypv(addr);
         break;
 #endif
     default:
+        DPRINTF_MMU("helper_lddf: need to check MMU idx %d\n", mem_idx);
         break;
     }
 #else
@@ -3321,24 +3621,25 @@ void helper_ldqf(target_ulong addr, int mem_idx)
     helper_check_align(addr, 7);
 #if !defined(CONFIG_USER_ONLY)
     switch (mem_idx) {
-    case 0:
+    case MMU_USER_IDX:
         u.ll.upper = ldq_user(addr);
         u.ll.lower = ldq_user(addr + 8);
         QT0 = u.q;
         break;
-    case 1:
+    case MMU_KERNEL_IDX:
         u.ll.upper = ldq_kernel(addr);
         u.ll.lower = ldq_kernel(addr + 8);
         QT0 = u.q;
         break;
 #ifdef TARGET_SPARC64
-    case 2:
+    case MMU_HYPV_IDX:
         u.ll.upper = ldq_hypv(addr);
         u.ll.lower = ldq_hypv(addr + 8);
         QT0 = u.q;
         break;
 #endif
     default:
+        DPRINTF_MMU("helper_ldqf: need to check MMU idx %d\n", mem_idx);
         break;
     }
 #else
@@ -3356,24 +3657,25 @@ void helper_stqf(target_ulong addr, int mem_idx)
     helper_check_align(addr, 7);
 #if !defined(CONFIG_USER_ONLY)
     switch (mem_idx) {
-    case 0:
+    case MMU_USER_IDX:
         u.q = QT0;
         stq_user(addr, u.ll.upper);
         stq_user(addr + 8, u.ll.lower);
         break;
-    case 1:
+    case MMU_KERNEL_IDX:
         u.q = QT0;
         stq_kernel(addr, u.ll.upper);
         stq_kernel(addr + 8, u.ll.lower);
         break;
 #ifdef TARGET_SPARC64
-    case 2:
+    case MMU_HYPV_IDX:
         u.q = QT0;
         stq_hypv(addr, u.ll.upper);
         stq_hypv(addr + 8, u.ll.lower);
         break;
 #endif
     default:
+        DPRINTF_MMU("helper_stqf: need to check MMU idx %d\n", mem_idx);
         break;
     }
 #else
@@ -3422,7 +3724,7 @@ void helper_ldxfsr(uint64_t new_fsr)
 void helper_debug(void)
 {
     env->exception_index = EXCP_DEBUG;
-    cpu_loop_exit();
+    cpu_loop_exit(env);
 }
 
 #ifndef TARGET_SPARC64
@@ -3812,12 +4114,6 @@ void helper_write_softint(uint64_t value)
 }
 #endif
 
-void helper_flush(target_ulong addr)
-{
-    addr &= ~7;
-    tb_invalidate_page_range(addr, addr + 8);
-}
-
 #ifdef TARGET_SPARC64
 #ifdef DEBUG_PCALL
 static const char * const excp_names[0x80] = {
@@ -3863,25 +4159,26 @@ trap_state* cpu_tsptr(CPUState* env)
 void do_interrupt(CPUState *env)
 {
     int intno = env->exception_index;
-    trap_statetsptr;
+    trap_state *tsptr;
 
 #ifdef DEBUG_PCALL
     if (qemu_loglevel_mask(CPU_LOG_INT)) {
         static int count;
         const char *name;
 
-        if (intno < 0 || intno >= 0x180)
+        if (intno < 0 || intno >= 0x180) {
             name = "Unknown";
-        else if (intno >= 0x100)
+        } else if (intno >= 0x100) {
             name = "Trap Instruction";
-        else if (intno >= 0xc0)
+        } else if (intno >= 0xc0) {
             name = "Window Fill";
-        else if (intno >= 0x80)
+        } else if (intno >= 0x80) {
             name = "Window Spill";
-        else {
+        else {
             name = excp_names[intno];
-            if (!name)
+            if (!name) {
                 name = "Unknown";
+            }
         }
 
         qemu_log("%6d: %s (v=%04x) pc=%016" PRIx64 " npc=%016" PRIx64
@@ -3897,7 +4194,7 @@ void do_interrupt(CPUState *env)
 
             qemu_log("       code=");
             ptr = (uint8_t *)env->pc;
-            for(i = 0; i < 16; i++) {
+            for (i = 0; i < 16; i++) {
                 qemu_log(" %02x", ldub(ptr + i));
             }
             qemu_log("\n");
@@ -3917,8 +4214,9 @@ void do_interrupt(CPUState *env)
         env->tl++;
     } else {
         env->pstate |= PS_RED;
-        if (env->tl < env->maxtl)
+        if (env->tl < env->maxtl) {
             env->tl++;
+        }
     }
     tsptr = cpu_tsptr(env);
 
@@ -4003,14 +4301,15 @@ void do_interrupt(CPUState *env)
         static int count;
         const char *name;
 
-        if (intno < 0 || intno >= 0x100)
+        if (intno < 0 || intno >= 0x100) {
             name = "Unknown";
-        else if (intno >= 0x80)
+        } else if (intno >= 0x80) {
             name = "Trap Instruction";
-        else {
+        else {
             name = excp_names[intno];
-            if (!name)
+            if (!name) {
                 name = "Unknown";
+            }
         }
 
         qemu_log("%6d: %s (v=%02x) pc=%08x npc=%08x SP=%08x\n",
@@ -4025,7 +4324,7 @@ void do_interrupt(CPUState *env)
 
             qemu_log("       code=");
             ptr = (uint8_t *)env->pc;
-            for(i = 0; i < 16; i++) {
+            for (i = 0; i < 16; i++) {
                 qemu_log(" %02x", ldub(ptr + i));
             }
             qemu_log("\n");
@@ -4052,6 +4351,13 @@ void do_interrupt(CPUState *env)
     env->pc = env->tbr;
     env->npc = env->pc + 4;
     env->exception_index = -1;
+
+#if !defined(CONFIG_USER_ONLY)
+    /* IRQ acknowledgment */
+    if ((intno & ~15) == TT_EXTINT && env->qemu_irq_ack != NULL) {
+        env->qemu_irq_ack(env->irq_manager, intno);
+    }
+#endif
 }
 #endif
 
@@ -4088,7 +4394,7 @@ static void cpu_restore_state2(void *retaddr)
         if (tb) {
             /* the PC is inside the translated code. It means that we have
                a virtual CPU fault */
-            cpu_restore_state(tb, env, pc, (void *)(long)env->cond);
+            cpu_restore_state(tb, env, pc);
         }
     }
 }
@@ -4121,7 +4427,7 @@ void tlb_fill(target_ulong addr, int is_write, int mmu_idx, void *retaddr)
     ret = cpu_sparc_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
     if (ret) {
         cpu_restore_state2(retaddr);
-        cpu_loop_exit();
+        cpu_loop_exit(env);
     }
     env = saved_env;
 }