summary refs log tree commit diff stats
path: root/target-sparc
diff options
context:
space:
mode:
Diffstat (limited to 'target-sparc')
-rw-r--r--target-sparc/cpu.h39
-rw-r--r--target-sparc/exec.h15
-rw-r--r--target-sparc/helper.c153
-rw-r--r--target-sparc/helper.h4
-rw-r--r--target-sparc/op_helper.c118
-rw-r--r--target-sparc/translate.c163
6 files changed, 360 insertions, 132 deletions
diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h
index 22ee2743d7..a51863cf07 100644
--- a/target-sparc/cpu.h
+++ b/target-sparc/cpu.h
@@ -290,18 +290,51 @@ enum {
 #endif
 
 #define TTE_VALID_BIT       (1ULL << 63)
+#define TTE_NFO_BIT         (1ULL << 60)
 #define TTE_USED_BIT        (1ULL << 41)
 #define TTE_LOCKED_BIT      (1ULL <<  6)
+#define TTE_SIDEEFFECT_BIT  (1ULL <<  3)
+#define TTE_PRIV_BIT        (1ULL <<  2)
+#define TTE_W_OK_BIT        (1ULL <<  1)
 #define TTE_GLOBAL_BIT      (1ULL <<  0)
 
 #define TTE_IS_VALID(tte)   ((tte) & TTE_VALID_BIT)
+#define TTE_IS_NFO(tte)     ((tte) & TTE_NFO_BIT)
 #define TTE_IS_USED(tte)    ((tte) & TTE_USED_BIT)
 #define TTE_IS_LOCKED(tte)  ((tte) & TTE_LOCKED_BIT)
+#define TTE_IS_SIDEEFFECT(tte) ((tte) & TTE_SIDEEFFECT_BIT)
+#define TTE_IS_PRIV(tte)    ((tte) & TTE_PRIV_BIT)
+#define TTE_IS_W_OK(tte)    ((tte) & TTE_W_OK_BIT)
 #define TTE_IS_GLOBAL(tte)  ((tte) & TTE_GLOBAL_BIT)
 
 #define TTE_SET_USED(tte)   ((tte) |= TTE_USED_BIT)
 #define TTE_SET_UNUSED(tte) ((tte) &= ~TTE_USED_BIT)
 
+#define TTE_PGSIZE(tte)     (((tte) >> 61) & 3ULL)
+#define TTE_PA(tte)         ((tte) & 0x1ffffffe000ULL)
+
+#define SFSR_NF_BIT         (1ULL << 24)   /* JPS1 NoFault */
+#define SFSR_TM_BIT         (1ULL << 15)   /* JPS1 TLB Miss */
+#define SFSR_FT_VA_IMMU_BIT (1ULL << 13)   /* USIIi VA out of range (IMMU) */
+#define SFSR_FT_VA_DMMU_BIT (1ULL << 12)   /* USIIi VA out of range (DMMU) */
+#define SFSR_FT_NFO_BIT     (1ULL << 11)   /* NFO page access */
+#define SFSR_FT_ILL_BIT     (1ULL << 10)   /* illegal LDA/STA ASI */
+#define SFSR_FT_ATOMIC_BIT  (1ULL <<  9)   /* atomic op on noncacheable area */
+#define SFSR_FT_NF_E_BIT    (1ULL <<  8)   /* NF access on side effect area */
+#define SFSR_FT_PRIV_BIT    (1ULL <<  7)   /* privilege violation */
+#define SFSR_PR_BIT         (1ULL <<  3)   /* privilege mode */
+#define SFSR_WRITE_BIT      (1ULL <<  2)   /* write access mode */
+#define SFSR_OW_BIT         (1ULL <<  1)   /* status overwritten */
+#define SFSR_VALID_BIT      (1ULL <<  0)   /* status valid */
+
+#define SFSR_ASI_SHIFT      16             /* 23:16 ASI value */
+#define SFSR_ASI_MASK       (0xffULL << SFSR_ASI_SHIFT)
+#define SFSR_CT_PRIMARY     (0ULL <<  4)   /* 5:4 context type */
+#define SFSR_CT_SECONDARY   (1ULL <<  4)
+#define SFSR_CT_NUCLEUS     (2ULL <<  4)
+#define SFSR_CT_NOTRANS     (3ULL <<  4)
+#define SFSR_CT_MASK        (3ULL <<  4)
+
 typedef struct SparcTLBEntry {
     uint64_t tag;
     uint64_t tte;
@@ -510,12 +543,14 @@ static inline int tlb_compare_context(const SparcTLBEntry *tlb,
 
 /* cpu-exec.c */
 #if !defined(CONFIG_USER_ONLY)
-void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec,
-                          int is_asi, int size);
+void cpu_unassigned_access(CPUState *env1, target_phys_addr_t addr,
+                           int is_write, int is_exec, int is_asi, int size);
+#if defined(TARGET_SPARC64)
 target_phys_addr_t cpu_get_phys_page_nofault(CPUState *env, target_ulong addr,
                                            int mmu_idx);
 
 #endif
+#endif
 int cpu_sparc_signal_handler(int host_signum, void *pinfo, void *puc);
 
 #define cpu_init cpu_sparc_init
diff --git a/target-sparc/exec.h b/target-sparc/exec.h
deleted file mode 100644
index 2395b0092f..0000000000
--- a/target-sparc/exec.h
+++ /dev/null
@@ -1,15 +0,0 @@
-#ifndef EXEC_SPARC_H
-#define EXEC_SPARC_H 1
-#include "config.h"
-#include "dyngen-exec.h"
-
-register struct CPUSPARCState *env asm(AREG0);
-
-#include "cpu.h"
-#include "exec-all.h"
-
-#if !defined(CONFIG_USER_ONLY)
-#include "softmmu_exec.h"
-#endif /* !defined(CONFIG_USER_ONLY) */
-
-#endif
diff --git a/target-sparc/helper.c b/target-sparc/helper.c
index 7eea1acbd5..efab885b83 100644
--- a/target-sparc/helper.c
+++ b/target-sparc/helper.c
@@ -378,7 +378,7 @@ static inline int ultrasparc_tag_match(SparcTLBEntry *tlb,
 {
     uint64_t mask;
 
-    switch ((tlb->tte >> 61) & 3) {
+    switch (TTE_PGSIZE(tlb->tte)) {
     default:
     case 0x0: // 8k
         mask = 0xffffffffffffe000ULL;
@@ -413,6 +413,7 @@ static int get_physical_address_data(CPUState *env,
 {
     unsigned int i;
     uint64_t context;
+    uint64_t sfsr = 0;
 
     int is_user = (mmu_idx == MMU_USER_IDX ||
                    mmu_idx == MMU_USER_SECONDARY_IDX);
@@ -427,54 +428,88 @@ static int get_physical_address_data(CPUState *env,
     case MMU_USER_IDX:
     case MMU_KERNEL_IDX:
         context = env->dmmu.mmu_primary_context & 0x1fff;
+        sfsr |= SFSR_CT_PRIMARY;
         break;
     case MMU_USER_SECONDARY_IDX:
     case MMU_KERNEL_SECONDARY_IDX:
         context = env->dmmu.mmu_secondary_context & 0x1fff;
+        sfsr |= SFSR_CT_SECONDARY;
         break;
     case MMU_NUCLEUS_IDX:
+        sfsr |= SFSR_CT_NUCLEUS;
+        /* FALLTHRU */
     default:
         context = 0;
         break;
     }
 
+    if (rw == 1) {
+        sfsr |= SFSR_WRITE_BIT;
+    } else if (rw == 4) {
+        sfsr |= SFSR_NF_BIT;
+    }
+
     for (i = 0; i < 64; i++) {
         // ctx match, vaddr match, valid?
         if (ultrasparc_tag_match(&env->dtlb[i], address, context, physical)) {
-
-            uint8_t fault_type = 0;
+            int do_fault = 0;
 
             // access ok?
-            if ((env->dtlb[i].tte & 0x4) && is_user) {
-                fault_type |= 1; /* privilege violation */
-                env->exception_index = TT_DFAULT;
+            /* multiple bits in SFSR.FT may be set on TT_DFAULT */
+            if (TTE_IS_PRIV(env->dtlb[i].tte) && is_user) {
+                do_fault = 1;
+                sfsr |= SFSR_FT_PRIV_BIT; /* privilege violation */
 
                 DPRINTF_MMU("DFAULT at %" PRIx64 " context %" PRIx64
                             " mmu_idx=%d tl=%d\n",
                             address, context, mmu_idx, env->tl);
-            } else if (!(env->dtlb[i].tte & 0x2) && (rw == 1)) {
+            }
+            if (rw == 4) {
+                if (TTE_IS_SIDEEFFECT(env->dtlb[i].tte)) {
+                    do_fault = 1;
+                    sfsr |= SFSR_FT_NF_E_BIT;
+                }
+            } else {
+                if (TTE_IS_NFO(env->dtlb[i].tte)) {
+                    do_fault = 1;
+                    sfsr |= SFSR_FT_NFO_BIT;
+                }
+            }
+
+            if (do_fault) {
+                /* faults above are reported with TT_DFAULT. */
+                env->exception_index = TT_DFAULT;
+            } else if (!TTE_IS_W_OK(env->dtlb[i].tte) && (rw == 1)) {
+                do_fault = 1;
                 env->exception_index = TT_DPROT;
 
                 DPRINTF_MMU("DPROT at %" PRIx64 " context %" PRIx64
                             " mmu_idx=%d tl=%d\n",
                             address, context, mmu_idx, env->tl);
-            } else {
+            }
+
+            if (!do_fault) {
                 *prot = PAGE_READ;
-                if (env->dtlb[i].tte & 0x2)
+                if (TTE_IS_W_OK(env->dtlb[i].tte)) {
                     *prot |= PAGE_WRITE;
+                }
 
                 TTE_SET_USED(env->dtlb[i].tte);
 
                 return 0;
             }
 
-            if (env->dmmu.sfsr & 1) /* Fault status register */
-                env->dmmu.sfsr = 2; /* overflow (not read before
-                                             another fault) */
+            if (env->dmmu.sfsr & SFSR_VALID_BIT) { /* Fault status register */
+                sfsr |= SFSR_OW_BIT; /* overflow (not read before
+                                        another fault) */
+            }
 
-            env->dmmu.sfsr |= (is_user << 3) | ((rw == 1) << 2) | 1;
+            if (env->pstate & PS_PRIV) {
+                sfsr |= SFSR_PR_BIT;
+            }
 
-            env->dmmu.sfsr |= (fault_type << 7);
+            /* FIXME: ASI field in SFSR must be set */
+            env->dmmu.sfsr = sfsr | SFSR_VALID_BIT;
 
             env->dmmu.sfar = address; /* Fault address register */
 
@@ -487,6 +522,11 @@ static int get_physical_address_data(CPUState *env,
     DPRINTF_MMU("DMISS at %" PRIx64 " context %" PRIx64 "\n",
                 address, context);
 
+    /*
+     * On MMU misses:
+     * - UltraSPARC IIi: SFSR and SFAR unmodified
+     * - JPS1: SFAR updated and some fields of SFSR updated
+     */
     env->dmmu.tag_access = (address & ~0x1fffULL) | context;
     env->exception_index = TT_DMISS;
     return 1;
@@ -522,11 +562,23 @@ static int get_physical_address_code(CPUState *env,
         if (ultrasparc_tag_match(&env->itlb[i],
                                  address, context, physical)) {
             // access ok?
-            if ((env->itlb[i].tte & 0x4) && is_user) {
-                if (env->immu.sfsr) /* Fault status register */
-                    env->immu.sfsr = 2; /* overflow (not read before
-                                             another fault) */
-                env->immu.sfsr |= (is_user << 3) | 1;
+            if (TTE_IS_PRIV(env->itlb[i].tte) && is_user) {
+                /* Fault status register */
+                if (env->immu.sfsr & SFSR_VALID_BIT) {
+                    env->immu.sfsr = SFSR_OW_BIT; /* overflow (not read before
+                                                     another fault) */
+                } else {
+                    env->immu.sfsr = 0;
+                }
+                if (env->pstate & PS_PRIV) {
+                    env->immu.sfsr |= SFSR_PR_BIT;
+                }
+                if (env->tl > 0) {
+                    env->immu.sfsr |= SFSR_CT_NUCLEUS;
+                }
+
+                /* FIXME: ASI field in SFSR must be set */
+                env->immu.sfsr |= SFSR_FT_PRIV_BIT | SFSR_VALID_BIT;
                 env->exception_index = TT_TFAULT;
 
                 env->immu.tag_access = (address & ~0x1fffULL) | context;
@@ -632,7 +684,7 @@ void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env)
     } else {
         (*cpu_fprintf)(f, "DMMU dump\n");
         for (i = 0; i < 64; i++) {
-            switch ((env->dtlb[i].tte >> 61) & 3) {
+            switch (TTE_PGSIZE(env->dtlb[i].tte)) {
             default:
             case 0x0:
                 mask = "  8k";
@@ -647,16 +699,17 @@ void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env)
                 mask = "  4M";
                 break;
             }
-            if ((env->dtlb[i].tte & 0x8000000000000000ULL) != 0) {
-                (*cpu_fprintf)(f, "[%02u] VA: %" PRIx64 ", PA: %" PRIx64
+            if (TTE_IS_VALID(env->dtlb[i].tte)) {
+                (*cpu_fprintf)(f, "[%02u] VA: %" PRIx64 ", PA: %llx"
                                ", %s, %s, %s, %s, ctx %" PRId64 " %s\n",
                                i,
                                env->dtlb[i].tag & (uint64_t)~0x1fffULL,
-                               env->dtlb[i].tte & (uint64_t)0x1ffffffe000ULL,
+                               TTE_PA(env->dtlb[i].tte),
                                mask,
-                               env->dtlb[i].tte & 0x4? "priv": "user",
-                               env->dtlb[i].tte & 0x2? "RW": "RO",
-                               env->dtlb[i].tte & 0x40? "locked": "unlocked",
+                               TTE_IS_PRIV(env->dtlb[i].tte) ? "priv" : "user",
+                               TTE_IS_W_OK(env->dtlb[i].tte) ? "RW" : "RO",
+                               TTE_IS_LOCKED(env->dtlb[i].tte) ?
+                               "locked" : "unlocked",
                                env->dtlb[i].tag & (uint64_t)0x1fffULL,
                                TTE_IS_GLOBAL(env->dtlb[i].tte)?
                                "global" : "local");
@@ -668,7 +721,7 @@ void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env)
     } else {
         (*cpu_fprintf)(f, "IMMU dump\n");
         for (i = 0; i < 64; i++) {
-            switch ((env->itlb[i].tte >> 61) & 3) {
+            switch (TTE_PGSIZE(env->itlb[i].tte)) {
             default:
             case 0x0:
                 mask = "  8k";
@@ -683,15 +736,16 @@ void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env)
                 mask = "  4M";
                 break;
             }
-            if ((env->itlb[i].tte & 0x8000000000000000ULL) != 0) {
-                (*cpu_fprintf)(f, "[%02u] VA: %" PRIx64 ", PA: %" PRIx64
+            if (TTE_IS_VALID(env->itlb[i].tte)) {
+                (*cpu_fprintf)(f, "[%02u] VA: %" PRIx64 ", PA: %llx"
                                ", %s, %s, %s, ctx %" PRId64 " %s\n",
                                i,
                                env->itlb[i].tag & (uint64_t)~0x1fffULL,
-                               env->itlb[i].tte & (uint64_t)0x1ffffffe000ULL,
+                               TTE_PA(env->itlb[i].tte),
                                mask,
-                               env->itlb[i].tte & 0x4? "priv": "user",
-                               env->itlb[i].tte & 0x40? "locked": "unlocked",
+                               TTE_IS_PRIV(env->itlb[i].tte) ? "priv" : "user",
+                               TTE_IS_LOCKED(env->itlb[i].tte) ?
+                               "locked" : "unlocked",
                                env->itlb[i].tag & (uint64_t)0x1fffULL,
                                TTE_IS_GLOBAL(env->itlb[i].tte)?
                                "global" : "local");
@@ -705,26 +759,43 @@ void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env)
 
 
 #if !defined(CONFIG_USER_ONLY)
+static int cpu_sparc_get_phys_page(CPUState *env, target_phys_addr_t *phys,
+                                   target_ulong addr, int rw, int mmu_idx)
+{
+    target_ulong page_size;
+    int prot, access_index;
+
+    return get_physical_address(env, phys, &prot, &access_index, addr, rw,
+                                mmu_idx, &page_size);
+}
+
+#if defined(TARGET_SPARC64)
 target_phys_addr_t cpu_get_phys_page_nofault(CPUState *env, target_ulong addr,
                                            int mmu_idx)
 {
     target_phys_addr_t phys_addr;
-    target_ulong page_size;
-    int prot, access_index;
 
-    if (get_physical_address(env, &phys_addr, &prot, &access_index, addr, 2,
-                             mmu_idx, &page_size) != 0)
-        if (get_physical_address(env, &phys_addr, &prot, &access_index, addr,
-                                 0, mmu_idx, &page_size) != 0)
-            return -1;
-    if (cpu_get_physical_page_desc(phys_addr) == IO_MEM_UNASSIGNED)
+    if (cpu_sparc_get_phys_page(env, &phys_addr, addr, 4, mmu_idx) != 0) {
         return -1;
+    }
     return phys_addr;
 }
+#endif
 
 target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
 {
-    return cpu_get_phys_page_nofault(env, addr, cpu_mmu_index(env));
+    target_phys_addr_t phys_addr;
+    int mmu_idx = cpu_mmu_index(env);
+
+    if (cpu_sparc_get_phys_page(env, &phys_addr, addr, 2, mmu_idx) != 0) {
+        if (cpu_sparc_get_phys_page(env, &phys_addr, addr, 0, mmu_idx) != 0) {
+            return -1;
+        }
+    }
+    if (cpu_get_physical_page_desc(phys_addr) == IO_MEM_UNASSIGNED) {
+        return -1;
+    }
+    return phys_addr;
 }
 #endif
 
diff --git a/target-sparc/helper.h b/target-sparc/helper.h
index 023f4d6023..2d36af3a31 100644
--- a/target-sparc/helper.h
+++ b/target-sparc/helper.h
@@ -148,8 +148,8 @@ F_HELPER_0_0(expand);
 VIS_HELPER(padd);
 VIS_HELPER(psub);
 #define VIS_CMPHELPER(name)                              \
-    F_HELPER_0_0(name##16);                              \
-    F_HELPER_0_0(name##32)
+    DEF_HELPER_0(f##name##16, i64);                      \
+    DEF_HELPER_0(f##name##32, i64)
 VIS_CMPHELPER(cmpgt);
 VIS_CMPHELPER(cmpeq);
 VIS_CMPHELPER(cmple);
diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c
index 15af27ba1f..5aeca2b06d 100644
--- a/target-sparc/op_helper.c
+++ b/target-sparc/op_helper.c
@@ -1,8 +1,13 @@
-#include "exec.h"
+#include "cpu.h"
+#include "dyngen-exec.h"
 #include "host-utils.h"
 #include "helper.h"
 #include "sysemu.h"
 
+#if !defined(CONFIG_USER_ONLY)
+#include "softmmu_exec.h"
+#endif
+
 //#define DEBUG_MMU
 //#define DEBUG_MXCC
 //#define DEBUG_UNALIGNED
@@ -79,9 +84,14 @@
 #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)
+#if !defined(CONFIG_USER_ONLY)
+static void do_unassigned_access(target_phys_addr_t addr, int is_write,
+                                 int is_exec, int is_asi, int size);
+#else
+#ifdef TARGET_SPARC64
 static void do_unassigned_access(target_ulong addr, int is_write, int is_exec,
-                          int is_asi, int size);
+                                 int is_asi, int size);
+#endif
 #endif
 
 #if defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY)
@@ -287,7 +297,8 @@ static inline int is_translating_asi(int asi)
      */
     switch (asi) {
     case 0x04 ... 0x11:
-    case 0x18 ... 0x19:
+    case 0x16 ... 0x19:
+    case 0x1E ... 0x1F:
     case 0x24 ... 0x2C:
     case 0x70 ... 0x73:
     case 0x78 ... 0x79:
@@ -525,6 +536,7 @@ typedef union {
     uint16_t w[4];
     int16_t sw[4];
     uint32_t l[2];
+    uint64_t ll;
     float64 d;
 } vis64;
 
@@ -789,32 +801,34 @@ VIS_HELPER(helper_fpadd, FADD)
 VIS_HELPER(helper_fpsub, FSUB)
 
 #define VIS_CMPHELPER(name, F)                                        \
-    void name##16(void)                                           \
+    uint64_t name##16(void)                                       \
     {                                                             \
         vis64 s, d;                                               \
                                                                   \
         s.d = DT0;                                                \
         d.d = DT1;                                                \
                                                                   \
-        d.VIS_W64(0) = F(d.VIS_W64(0), s.VIS_W64(0))? 1: 0;       \
-        d.VIS_W64(0) |= F(d.VIS_W64(1), s.VIS_W64(1))? 2: 0;      \
-        d.VIS_W64(0) |= F(d.VIS_W64(2), s.VIS_W64(2))? 4: 0;      \
-        d.VIS_W64(0) |= F(d.VIS_W64(3), s.VIS_W64(3))? 8: 0;      \
+        d.VIS_W64(0) = F(s.VIS_W64(0), d.VIS_W64(0)) ? 1 : 0;     \
+        d.VIS_W64(0) |= F(s.VIS_W64(1), d.VIS_W64(1)) ? 2 : 0;    \
+        d.VIS_W64(0) |= F(s.VIS_W64(2), d.VIS_W64(2)) ? 4 : 0;    \
+        d.VIS_W64(0) |= F(s.VIS_W64(3), d.VIS_W64(3)) ? 8 : 0;    \
+        d.VIS_W64(1) = d.VIS_W64(2) = d.VIS_W64(3) = 0;           \
                                                                   \
-        DT0 = d.d;                                                \
+        return d.ll;                                              \
     }                                                             \
                                                                   \
-    void name##32(void)                                           \
+    uint64_t name##32(void)                                       \
     {                                                             \
         vis64 s, d;                                               \
                                                                   \
         s.d = DT0;                                                \
         d.d = DT1;                                                \
                                                                   \
-        d.VIS_L64(0) = F(d.VIS_L64(0), s.VIS_L64(0))? 1: 0;       \
-        d.VIS_L64(0) |= F(d.VIS_L64(1), s.VIS_L64(1))? 2: 0;      \
+        d.VIS_L64(0) = F(s.VIS_L64(0), d.VIS_L64(0)) ? 1 : 0;     \
+        d.VIS_L64(0) |= F(s.VIS_L64(1), d.VIS_L64(1)) ? 2 : 0;    \
+        d.VIS_L64(1) = 0;                                         \
                                                                   \
-        DT0 = d.d;                                                \
+        return d.ll;                                              \
     }
 
 #define FCMPGT(a, b) ((a) > (b))
@@ -2558,24 +2572,30 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
     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
-    case 0x83: // Secondary no-fault
-    case 0x8b: // Secondary no-fault LE
-        {
-            /* secondary space access has lowest asi bit equal to 1 */
-            int access_mmu_idx = ( asi & 1 ) ? MMU_KERNEL_IDX
-                                             : MMU_KERNEL_SECONDARY_IDX;
+    /* process nonfaulting loads first */
+    if ((asi & 0xf6) == 0x82) {
+        int mmu_idx;
 
-            if (cpu_get_phys_page_nofault(env, addr, access_mmu_idx) == -1ULL) {
+        /* secondary space access has lowest asi bit equal to 1 */
+        if (env->pstate & PS_PRIV) {
+            mmu_idx = (asi & 1) ? MMU_KERNEL_SECONDARY_IDX : MMU_KERNEL_IDX;
+        } else {
+            mmu_idx = (asi & 1) ? MMU_USER_SECONDARY_IDX : MMU_USER_IDX;
+        }
+
+        if (cpu_get_phys_page_nofault(env, addr, mmu_idx) == -1ULL) {
 #ifdef DEBUG_ASI
-                dump_asi("read ", last_addr, asi, size, ret);
+            dump_asi("read ", last_addr, asi, size, ret);
 #endif
-                return 0;
-            }
+            /* env->exception_index is set in get_physical_address_data(). */
+            raise_exception(env->exception_index);
         }
-        // Fall through
+
+        /* convert nonfaulting load ASIs to normal load ASIs */
+        asi &= ~0x02;
+    }
+
+    switch (asi) {
     case 0x10: // As if user primary
     case 0x11: // As if user secondary
     case 0x18: // As if user primary LE
@@ -2853,8 +2873,6 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
     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);
@@ -4231,16 +4249,11 @@ void tlb_fill(target_ulong addr, int is_write, int mmu_idx, void *retaddr)
 
 #ifndef TARGET_SPARC64
 #if !defined(CONFIG_USER_ONLY)
-void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec,
-                          int is_asi, int size)
+static void do_unassigned_access(target_phys_addr_t addr, int is_write,
+                                 int is_exec, int is_asi, int size)
 {
-    CPUState *saved_env;
     int fault_type;
 
-    /* XXX: hack to restore env in all cases, even if not called from
-       generated code */
-    saved_env = env;
-    env = cpu_single_env;
 #ifdef DEBUG_UNASSIGNED
     if (is_asi)
         printf("Unassigned mem %s access of %d byte%s to " TARGET_FMT_plx
@@ -4288,8 +4301,6 @@ void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec,
     if (env->mmuregs[0] & MMU_NF) {
         tlb_flush(env, 1);
     }
-
-    env = saved_env;
 }
 #endif
 #else
@@ -4297,17 +4308,10 @@ void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec,
 static void do_unassigned_access(target_ulong addr, int is_write, int is_exec,
                           int is_asi, int size)
 #else
-void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec,
-                          int is_asi, int size)
+static void do_unassigned_access(target_phys_addr_t addr, int is_write,
+                                 int is_exec, int is_asi, int size)
 #endif
 {
-    CPUState *saved_env;
-
-    /* XXX: hack to restore env in all cases, even if not called from
-       generated code */
-    saved_env = env;
-    env = cpu_single_env;
-
 #ifdef DEBUG_UNASSIGNED
     printf("Unassigned mem access to " TARGET_FMT_plx " from " TARGET_FMT_lx
            "\n", addr, env->pc);
@@ -4317,8 +4321,6 @@ void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec,
         raise_exception(TT_CODE_ACCESS);
     else
         raise_exception(TT_DATA_ACCESS);
-
-    env = saved_env;
 }
 #endif
 
@@ -4347,3 +4349,19 @@ void helper_tick_set_limit(void *opaque, uint64_t limit)
 #endif
 }
 #endif
+
+#if !defined(CONFIG_USER_ONLY)
+void cpu_unassigned_access(CPUState *env1, target_phys_addr_t addr,
+                           int is_write, int is_exec, int is_asi, int size)
+{
+    CPUState *saved_env;
+
+    saved_env = env;
+    env = env1;
+    /* Ignore unassigned accesses outside of CPU context */
+    if (env1) {
+        do_unassigned_access(addr, is_write, is_exec, is_asi, size);
+    }
+    env = saved_env;
+}
+#endif
diff --git a/target-sparc/translate.c b/target-sparc/translate.c
index 27c2cf98e8..958fbc5a9d 100644
--- a/target-sparc/translate.c
+++ b/target-sparc/translate.c
@@ -1558,6 +1558,13 @@ static int gen_trap_ifnofpu(DisasContext *dc, TCGv r_cond)
     return 0;
 }
 
+static inline void gen_update_fprs_dirty(int rd)
+{
+#if defined(TARGET_SPARC64)
+    tcg_gen_ori_i32(cpu_fprs, cpu_fprs, (rd < 32) ? 1 : 2);
+#endif
+}
+
 static inline void gen_op_clear_ieee_excp_and_FTT(void)
 {
     tcg_gen_andi_tl(cpu_fsr, cpu_fsr, FSR_FTT_CEXC_NMASK);
@@ -2351,12 +2358,15 @@ static void disas_sparc_insn(DisasContext * dc)
                 switch (xop) {
                 case 0x1: /* fmovs */
                     tcg_gen_mov_i32(cpu_fpr[rd], cpu_fpr[rs2]);
+                    gen_update_fprs_dirty(rd);
                     break;
                 case 0x5: /* fnegs */
                     gen_helper_fnegs(cpu_fpr[rd], cpu_fpr[rs2]);
+                    gen_update_fprs_dirty(rd);
                     break;
                 case 0x9: /* fabss */
                     gen_helper_fabss(cpu_fpr[rd], cpu_fpr[rs2]);
+                    gen_update_fprs_dirty(rd);
                     break;
                 case 0x29: /* fsqrts */
                     CHECK_FPU_FEATURE(dc, FSQRT);
@@ -2364,6 +2374,7 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_helper_fsqrts(cpu_tmp32, cpu_fpr[rs2]);
                     gen_helper_check_ieee_exceptions();
                     tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
+                    gen_update_fprs_dirty(rd);
                     break;
                 case 0x2a: /* fsqrtd */
                     CHECK_FPU_FEATURE(dc, FSQRT);
@@ -2372,6 +2383,7 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_helper_fsqrtd();
                     gen_helper_check_ieee_exceptions();
                     gen_op_store_DT0_fpr(DFPREG(rd));
+                    gen_update_fprs_dirty(DFPREG(rd));
                     break;
                 case 0x2b: /* fsqrtq */
                     CHECK_FPU_FEATURE(dc, FLOAT128);
@@ -2380,12 +2392,14 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_helper_fsqrtq();
                     gen_helper_check_ieee_exceptions();
                     gen_op_store_QT0_fpr(QFPREG(rd));
+                    gen_update_fprs_dirty(QFPREG(rd));
                     break;
                 case 0x41: /* fadds */
                     gen_clear_float_exceptions();
                     gen_helper_fadds(cpu_tmp32, cpu_fpr[rs1], cpu_fpr[rs2]);
                     gen_helper_check_ieee_exceptions();
                     tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
+                    gen_update_fprs_dirty(rd);
                     break;
                 case 0x42: /* faddd */
                     gen_op_load_fpr_DT0(DFPREG(rs1));
@@ -2394,6 +2408,7 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_helper_faddd();
                     gen_helper_check_ieee_exceptions();
                     gen_op_store_DT0_fpr(DFPREG(rd));
+                    gen_update_fprs_dirty(DFPREG(rd));
                     break;
                 case 0x43: /* faddq */
                     CHECK_FPU_FEATURE(dc, FLOAT128);
@@ -2403,12 +2418,14 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_helper_faddq();
                     gen_helper_check_ieee_exceptions();
                     gen_op_store_QT0_fpr(QFPREG(rd));
+                    gen_update_fprs_dirty(QFPREG(rd));
                     break;
                 case 0x45: /* fsubs */
                     gen_clear_float_exceptions();
                     gen_helper_fsubs(cpu_tmp32, cpu_fpr[rs1], cpu_fpr[rs2]);
                     gen_helper_check_ieee_exceptions();
                     tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
+                    gen_update_fprs_dirty(rd);
                     break;
                 case 0x46: /* fsubd */
                     gen_op_load_fpr_DT0(DFPREG(rs1));
@@ -2417,6 +2434,7 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_helper_fsubd();
                     gen_helper_check_ieee_exceptions();
                     gen_op_store_DT0_fpr(DFPREG(rd));
+                    gen_update_fprs_dirty(DFPREG(rd));
                     break;
                 case 0x47: /* fsubq */
                     CHECK_FPU_FEATURE(dc, FLOAT128);
@@ -2426,6 +2444,7 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_helper_fsubq();
                     gen_helper_check_ieee_exceptions();
                     gen_op_store_QT0_fpr(QFPREG(rd));
+                    gen_update_fprs_dirty(QFPREG(rd));
                     break;
                 case 0x49: /* fmuls */
                     CHECK_FPU_FEATURE(dc, FMUL);
@@ -2433,6 +2452,7 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_helper_fmuls(cpu_tmp32, cpu_fpr[rs1], cpu_fpr[rs2]);
                     gen_helper_check_ieee_exceptions();
                     tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
+                    gen_update_fprs_dirty(rd);
                     break;
                 case 0x4a: /* fmuld */
                     CHECK_FPU_FEATURE(dc, FMUL);
@@ -2442,6 +2462,7 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_helper_fmuld();
                     gen_helper_check_ieee_exceptions();
                     gen_op_store_DT0_fpr(DFPREG(rd));
+                    gen_update_fprs_dirty(DFPREG(rd));
                     break;
                 case 0x4b: /* fmulq */
                     CHECK_FPU_FEATURE(dc, FLOAT128);
@@ -2452,12 +2473,14 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_helper_fmulq();
                     gen_helper_check_ieee_exceptions();
                     gen_op_store_QT0_fpr(QFPREG(rd));
+                    gen_update_fprs_dirty(QFPREG(rd));
                     break;
                 case 0x4d: /* fdivs */
                     gen_clear_float_exceptions();
                     gen_helper_fdivs(cpu_tmp32, cpu_fpr[rs1], cpu_fpr[rs2]);
                     gen_helper_check_ieee_exceptions();
                     tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
+                    gen_update_fprs_dirty(rd);
                     break;
                 case 0x4e: /* fdivd */
                     gen_op_load_fpr_DT0(DFPREG(rs1));
@@ -2466,6 +2489,7 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_helper_fdivd();
                     gen_helper_check_ieee_exceptions();
                     gen_op_store_DT0_fpr(DFPREG(rd));
+                    gen_update_fprs_dirty(DFPREG(rd));
                     break;
                 case 0x4f: /* fdivq */
                     CHECK_FPU_FEATURE(dc, FLOAT128);
@@ -2475,6 +2499,7 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_helper_fdivq();
                     gen_helper_check_ieee_exceptions();
                     gen_op_store_QT0_fpr(QFPREG(rd));
+                    gen_update_fprs_dirty(QFPREG(rd));
                     break;
                 case 0x69: /* fsmuld */
                     CHECK_FPU_FEATURE(dc, FSMULD);
@@ -2482,6 +2507,7 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_helper_fsmuld(cpu_fpr[rs1], cpu_fpr[rs2]);
                     gen_helper_check_ieee_exceptions();
                     gen_op_store_DT0_fpr(DFPREG(rd));
+                    gen_update_fprs_dirty(DFPREG(rd));
                     break;
                 case 0x6e: /* fdmulq */
                     CHECK_FPU_FEATURE(dc, FLOAT128);
@@ -2491,12 +2517,14 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_helper_fdmulq();
                     gen_helper_check_ieee_exceptions();
                     gen_op_store_QT0_fpr(QFPREG(rd));
+                    gen_update_fprs_dirty(QFPREG(rd));
                     break;
                 case 0xc4: /* fitos */
                     gen_clear_float_exceptions();
                     gen_helper_fitos(cpu_tmp32, cpu_fpr[rs2]);
                     gen_helper_check_ieee_exceptions();
                     tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
+                    gen_update_fprs_dirty(rd);
                     break;
                 case 0xc6: /* fdtos */
                     gen_op_load_fpr_DT1(DFPREG(rs2));
@@ -2504,6 +2532,7 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_helper_fdtos(cpu_tmp32);
                     gen_helper_check_ieee_exceptions();
                     tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
+                    gen_update_fprs_dirty(rd);
                     break;
                 case 0xc7: /* fqtos */
                     CHECK_FPU_FEATURE(dc, FLOAT128);
@@ -2512,14 +2541,17 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_helper_fqtos(cpu_tmp32);
                     gen_helper_check_ieee_exceptions();
                     tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
+                    gen_update_fprs_dirty(rd);
                     break;
                 case 0xc8: /* fitod */
                     gen_helper_fitod(cpu_fpr[rs2]);
                     gen_op_store_DT0_fpr(DFPREG(rd));
+                    gen_update_fprs_dirty(DFPREG(rd));
                     break;
                 case 0xc9: /* fstod */
                     gen_helper_fstod(cpu_fpr[rs2]);
                     gen_op_store_DT0_fpr(DFPREG(rd));
+                    gen_update_fprs_dirty(DFPREG(rd));
                     break;
                 case 0xcb: /* fqtod */
                     CHECK_FPU_FEATURE(dc, FLOAT128);
@@ -2528,28 +2560,33 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_helper_fqtod();
                     gen_helper_check_ieee_exceptions();
                     gen_op_store_DT0_fpr(DFPREG(rd));
+                    gen_update_fprs_dirty(DFPREG(rd));
                     break;
                 case 0xcc: /* fitoq */
                     CHECK_FPU_FEATURE(dc, FLOAT128);
                     gen_helper_fitoq(cpu_fpr[rs2]);
                     gen_op_store_QT0_fpr(QFPREG(rd));
+                    gen_update_fprs_dirty(QFPREG(rd));
                     break;
                 case 0xcd: /* fstoq */
                     CHECK_FPU_FEATURE(dc, FLOAT128);
                     gen_helper_fstoq(cpu_fpr[rs2]);
                     gen_op_store_QT0_fpr(QFPREG(rd));
+                    gen_update_fprs_dirty(QFPREG(rd));
                     break;
                 case 0xce: /* fdtoq */
                     CHECK_FPU_FEATURE(dc, FLOAT128);
                     gen_op_load_fpr_DT1(DFPREG(rs2));
                     gen_helper_fdtoq();
                     gen_op_store_QT0_fpr(QFPREG(rd));
+                    gen_update_fprs_dirty(QFPREG(rd));
                     break;
                 case 0xd1: /* fstoi */
                     gen_clear_float_exceptions();
                     gen_helper_fstoi(cpu_tmp32, cpu_fpr[rs2]);
                     gen_helper_check_ieee_exceptions();
                     tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
+                    gen_update_fprs_dirty(rd);
                     break;
                 case 0xd2: /* fdtoi */
                     gen_op_load_fpr_DT1(DFPREG(rs2));
@@ -2557,6 +2594,7 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_helper_fdtoi(cpu_tmp32);
                     gen_helper_check_ieee_exceptions();
                     tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
+                    gen_update_fprs_dirty(rd);
                     break;
                 case 0xd3: /* fqtoi */
                     CHECK_FPU_FEATURE(dc, FLOAT128);
@@ -2565,12 +2603,14 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_helper_fqtoi(cpu_tmp32);
                     gen_helper_check_ieee_exceptions();
                     tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
+                    gen_update_fprs_dirty(rd);
                     break;
 #ifdef TARGET_SPARC64
                 case 0x2: /* V9 fmovd */
                     tcg_gen_mov_i32(cpu_fpr[DFPREG(rd)], cpu_fpr[DFPREG(rs2)]);
                     tcg_gen_mov_i32(cpu_fpr[DFPREG(rd) + 1],
                                     cpu_fpr[DFPREG(rs2) + 1]);
+                    gen_update_fprs_dirty(DFPREG(rd));
                     break;
                 case 0x3: /* V9 fmovq */
                     CHECK_FPU_FEATURE(dc, FLOAT128);
@@ -2581,34 +2621,40 @@ static void disas_sparc_insn(DisasContext * dc)
                                     cpu_fpr[QFPREG(rs2) + 2]);
                     tcg_gen_mov_i32(cpu_fpr[QFPREG(rd) + 3],
                                     cpu_fpr[QFPREG(rs2) + 3]);
+                    gen_update_fprs_dirty(QFPREG(rd));
                     break;
                 case 0x6: /* V9 fnegd */
                     gen_op_load_fpr_DT1(DFPREG(rs2));
                     gen_helper_fnegd();
                     gen_op_store_DT0_fpr(DFPREG(rd));
+                    gen_update_fprs_dirty(DFPREG(rd));
                     break;
                 case 0x7: /* V9 fnegq */
                     CHECK_FPU_FEATURE(dc, FLOAT128);
                     gen_op_load_fpr_QT1(QFPREG(rs2));
                     gen_helper_fnegq();
                     gen_op_store_QT0_fpr(QFPREG(rd));
+                    gen_update_fprs_dirty(QFPREG(rd));
                     break;
                 case 0xa: /* V9 fabsd */
                     gen_op_load_fpr_DT1(DFPREG(rs2));
                     gen_helper_fabsd();
                     gen_op_store_DT0_fpr(DFPREG(rd));
+                    gen_update_fprs_dirty(DFPREG(rd));
                     break;
                 case 0xb: /* V9 fabsq */
                     CHECK_FPU_FEATURE(dc, FLOAT128);
                     gen_op_load_fpr_QT1(QFPREG(rs2));
                     gen_helper_fabsq();
                     gen_op_store_QT0_fpr(QFPREG(rd));
+                    gen_update_fprs_dirty(QFPREG(rd));
                     break;
                 case 0x81: /* V9 fstox */
                     gen_clear_float_exceptions();
                     gen_helper_fstox(cpu_fpr[rs2]);
                     gen_helper_check_ieee_exceptions();
                     gen_op_store_DT0_fpr(DFPREG(rd));
+                    gen_update_fprs_dirty(DFPREG(rd));
                     break;
                 case 0x82: /* V9 fdtox */
                     gen_op_load_fpr_DT1(DFPREG(rs2));
@@ -2616,6 +2662,7 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_helper_fdtox();
                     gen_helper_check_ieee_exceptions();
                     gen_op_store_DT0_fpr(DFPREG(rd));
+                    gen_update_fprs_dirty(DFPREG(rd));
                     break;
                 case 0x83: /* V9 fqtox */
                     CHECK_FPU_FEATURE(dc, FLOAT128);
@@ -2624,6 +2671,7 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_helper_fqtox();
                     gen_helper_check_ieee_exceptions();
                     gen_op_store_DT0_fpr(DFPREG(rd));
+                    gen_update_fprs_dirty(DFPREG(rd));
                     break;
                 case 0x84: /* V9 fxtos */
                     gen_op_load_fpr_DT1(DFPREG(rs2));
@@ -2631,6 +2679,7 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_helper_fxtos(cpu_tmp32);
                     gen_helper_check_ieee_exceptions();
                     tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
+                    gen_update_fprs_dirty(rd);
                     break;
                 case 0x88: /* V9 fxtod */
                     gen_op_load_fpr_DT1(DFPREG(rs2));
@@ -2638,6 +2687,7 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_helper_fxtod();
                     gen_helper_check_ieee_exceptions();
                     gen_op_store_DT0_fpr(DFPREG(rd));
+                    gen_update_fprs_dirty(DFPREG(rd));
                     break;
                 case 0x8c: /* V9 fxtoq */
                     CHECK_FPU_FEATURE(dc, FLOAT128);
@@ -2646,6 +2696,7 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_helper_fxtoq();
                     gen_helper_check_ieee_exceptions();
                     gen_op_store_QT0_fpr(QFPREG(rd));
+                    gen_update_fprs_dirty(QFPREG(rd));
                     break;
 #endif
                 default:
@@ -2672,6 +2723,7 @@ static void disas_sparc_insn(DisasContext * dc)
                     tcg_gen_brcondi_tl(gen_tcg_cond_reg[cond], cpu_src1,
                                        0, l1);
                     tcg_gen_mov_i32(cpu_fpr[rd], cpu_fpr[rs2]);
+                    gen_update_fprs_dirty(rd);
                     gen_set_label(l1);
                     break;
                 } else if ((xop & 0x11f) == 0x006) { // V9 fmovdr
@@ -2684,6 +2736,7 @@ static void disas_sparc_insn(DisasContext * dc)
                                        0, l1);
                     tcg_gen_mov_i32(cpu_fpr[DFPREG(rd)], cpu_fpr[DFPREG(rs2)]);
                     tcg_gen_mov_i32(cpu_fpr[DFPREG(rd) + 1], cpu_fpr[DFPREG(rs2) + 1]);
+                    gen_update_fprs_dirty(DFPREG(rd));
                     gen_set_label(l1);
                     break;
                 } else if ((xop & 0x11f) == 0x007) { // V9 fmovqr
@@ -2699,6 +2752,7 @@ static void disas_sparc_insn(DisasContext * dc)
                     tcg_gen_mov_i32(cpu_fpr[QFPREG(rd) + 1], cpu_fpr[QFPREG(rs2) + 1]);
                     tcg_gen_mov_i32(cpu_fpr[QFPREG(rd) + 2], cpu_fpr[QFPREG(rs2) + 2]);
                     tcg_gen_mov_i32(cpu_fpr[QFPREG(rd) + 3], cpu_fpr[QFPREG(rs2) + 3]);
+                    gen_update_fprs_dirty(QFPREG(rd));
                     gen_set_label(l1);
                     break;
                 }
@@ -2717,6 +2771,7 @@ static void disas_sparc_insn(DisasContext * dc)
                         tcg_gen_brcondi_tl(TCG_COND_EQ, r_cond,         \
                                            0, l1);                      \
                         tcg_gen_mov_i32(cpu_fpr[rd], cpu_fpr[rs2]);     \
+                        gen_update_fprs_dirty(rd);                      \
                         gen_set_label(l1);                              \
                         tcg_temp_free(r_cond);                          \
                     }
@@ -2735,6 +2790,7 @@ static void disas_sparc_insn(DisasContext * dc)
                                         cpu_fpr[DFPREG(rs2)]);          \
                         tcg_gen_mov_i32(cpu_fpr[DFPREG(rd) + 1],        \
                                         cpu_fpr[DFPREG(rs2) + 1]);      \
+                        gen_update_fprs_dirty(DFPREG(rd));              \
                         gen_set_label(l1);                              \
                         tcg_temp_free(r_cond);                          \
                     }
@@ -2757,6 +2813,7 @@ static void disas_sparc_insn(DisasContext * dc)
                                         cpu_fpr[QFPREG(rs2) + 2]);      \
                         tcg_gen_mov_i32(cpu_fpr[QFPREG(rd) + 3],        \
                                         cpu_fpr[QFPREG(rs2) + 3]);      \
+                        gen_update_fprs_dirty(QFPREG(rd));              \
                         gen_set_label(l1);                              \
                         tcg_temp_free(r_cond);                          \
                     }
@@ -2815,6 +2872,7 @@ static void disas_sparc_insn(DisasContext * dc)
                         tcg_gen_brcondi_tl(TCG_COND_EQ, r_cond,         \
                                            0, l1);                      \
                         tcg_gen_mov_i32(cpu_fpr[rd], cpu_fpr[rs2]);     \
+                        gen_update_fprs_dirty(rd);                      \
                         gen_set_label(l1);                              \
                         tcg_temp_free(r_cond);                          \
                     }
@@ -2833,6 +2891,7 @@ static void disas_sparc_insn(DisasContext * dc)
                                         cpu_fpr[DFPREG(rs2)]);          \
                         tcg_gen_mov_i32(cpu_fpr[DFPREG(rd) + 1],        \
                                         cpu_fpr[DFPREG(rs2) + 1]);      \
+                        gen_update_fprs_dirty(DFPREG(rd));              \
                         gen_set_label(l1);                              \
                         tcg_temp_free(r_cond);                          \
                     }
@@ -2855,6 +2914,7 @@ static void disas_sparc_insn(DisasContext * dc)
                                         cpu_fpr[QFPREG(rs2) + 2]);      \
                         tcg_gen_mov_i32(cpu_fpr[QFPREG(rd) + 3],        \
                                         cpu_fpr[QFPREG(rs2) + 3]);      \
+                        gen_update_fprs_dirty(QFPREG(rd));              \
                         gen_set_label(l1);                              \
                         tcg_temp_free(r_cond);                          \
                     }
@@ -2864,6 +2924,7 @@ static void disas_sparc_insn(DisasContext * dc)
                         break;
                     case 0x102: /* V9 fmovdcc %icc */
                         FMOVDCC(0);
+                        break;
                     case 0x103: /* V9 fmovqcc %icc */
                         CHECK_FPU_FEATURE(dc, FLOAT128);
                         FMOVQCC(0);
@@ -3789,57 +3850,57 @@ static void disas_sparc_insn(DisasContext * dc)
                     CHECK_FPU_FEATURE(dc, VIS1);
                     gen_op_load_fpr_DT0(DFPREG(rs1));
                     gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_fcmple16();
-                    gen_op_store_DT0_fpr(DFPREG(rd));
+                    gen_helper_fcmple16(cpu_dst);
+                    gen_movl_TN_reg(rd, cpu_dst);
                     break;
                 case 0x022: /* VIS I fcmpne16 */
                     CHECK_FPU_FEATURE(dc, VIS1);
                     gen_op_load_fpr_DT0(DFPREG(rs1));
                     gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_fcmpne16();
-                    gen_op_store_DT0_fpr(DFPREG(rd));
+                    gen_helper_fcmpne16(cpu_dst);
+                    gen_movl_TN_reg(rd, cpu_dst);
                     break;
                 case 0x024: /* VIS I fcmple32 */
                     CHECK_FPU_FEATURE(dc, VIS1);
                     gen_op_load_fpr_DT0(DFPREG(rs1));
                     gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_fcmple32();
-                    gen_op_store_DT0_fpr(DFPREG(rd));
+                    gen_helper_fcmple32(cpu_dst);
+                    gen_movl_TN_reg(rd, cpu_dst);
                     break;
                 case 0x026: /* VIS I fcmpne32 */
                     CHECK_FPU_FEATURE(dc, VIS1);
                     gen_op_load_fpr_DT0(DFPREG(rs1));
                     gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_fcmpne32();
-                    gen_op_store_DT0_fpr(DFPREG(rd));
+                    gen_helper_fcmpne32(cpu_dst);
+                    gen_movl_TN_reg(rd, cpu_dst);
                     break;
                 case 0x028: /* VIS I fcmpgt16 */
                     CHECK_FPU_FEATURE(dc, VIS1);
                     gen_op_load_fpr_DT0(DFPREG(rs1));
                     gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_fcmpgt16();
-                    gen_op_store_DT0_fpr(DFPREG(rd));
+                    gen_helper_fcmpgt16(cpu_dst);
+                    gen_movl_TN_reg(rd, cpu_dst);
                     break;
                 case 0x02a: /* VIS I fcmpeq16 */
                     CHECK_FPU_FEATURE(dc, VIS1);
                     gen_op_load_fpr_DT0(DFPREG(rs1));
                     gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_fcmpeq16();
-                    gen_op_store_DT0_fpr(DFPREG(rd));
+                    gen_helper_fcmpeq16(cpu_dst);
+                    gen_movl_TN_reg(rd, cpu_dst);
                     break;
                 case 0x02c: /* VIS I fcmpgt32 */
                     CHECK_FPU_FEATURE(dc, VIS1);
                     gen_op_load_fpr_DT0(DFPREG(rs1));
                     gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_fcmpgt32();
-                    gen_op_store_DT0_fpr(DFPREG(rd));
+                    gen_helper_fcmpgt32(cpu_dst);
+                    gen_movl_TN_reg(rd, cpu_dst);
                     break;
                 case 0x02e: /* VIS I fcmpeq32 */
                     CHECK_FPU_FEATURE(dc, VIS1);
                     gen_op_load_fpr_DT0(DFPREG(rs1));
                     gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_fcmpeq32();
-                    gen_op_store_DT0_fpr(DFPREG(rd));
+                    gen_helper_fcmpeq32(cpu_dst);
+                    gen_movl_TN_reg(rd, cpu_dst);
                     break;
                 case 0x031: /* VIS I fmul8x16 */
                     CHECK_FPU_FEATURE(dc, VIS1);
@@ -3847,6 +3908,7 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_op_load_fpr_DT1(DFPREG(rs2));
                     gen_helper_fmul8x16();
                     gen_op_store_DT0_fpr(DFPREG(rd));
+                    gen_update_fprs_dirty(DFPREG(rd));
                     break;
                 case 0x033: /* VIS I fmul8x16au */
                     CHECK_FPU_FEATURE(dc, VIS1);
@@ -3854,6 +3916,7 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_op_load_fpr_DT1(DFPREG(rs2));
                     gen_helper_fmul8x16au();
                     gen_op_store_DT0_fpr(DFPREG(rd));
+                    gen_update_fprs_dirty(DFPREG(rd));
                     break;
                 case 0x035: /* VIS I fmul8x16al */
                     CHECK_FPU_FEATURE(dc, VIS1);
@@ -3861,6 +3924,7 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_op_load_fpr_DT1(DFPREG(rs2));
                     gen_helper_fmul8x16al();
                     gen_op_store_DT0_fpr(DFPREG(rd));
+                    gen_update_fprs_dirty(DFPREG(rd));
                     break;
                 case 0x036: /* VIS I fmul8sux16 */
                     CHECK_FPU_FEATURE(dc, VIS1);
@@ -3868,6 +3932,7 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_op_load_fpr_DT1(DFPREG(rs2));
                     gen_helper_fmul8sux16();
                     gen_op_store_DT0_fpr(DFPREG(rd));
+                    gen_update_fprs_dirty(DFPREG(rd));
                     break;
                 case 0x037: /* VIS I fmul8ulx16 */
                     CHECK_FPU_FEATURE(dc, VIS1);
@@ -3875,6 +3940,7 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_op_load_fpr_DT1(DFPREG(rs2));
                     gen_helper_fmul8ulx16();
                     gen_op_store_DT0_fpr(DFPREG(rd));
+                    gen_update_fprs_dirty(DFPREG(rd));
                     break;
                 case 0x038: /* VIS I fmuld8sux16 */
                     CHECK_FPU_FEATURE(dc, VIS1);
@@ -3882,6 +3948,7 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_op_load_fpr_DT1(DFPREG(rs2));
                     gen_helper_fmuld8sux16();
                     gen_op_store_DT0_fpr(DFPREG(rd));
+                    gen_update_fprs_dirty(DFPREG(rd));
                     break;
                 case 0x039: /* VIS I fmuld8ulx16 */
                     CHECK_FPU_FEATURE(dc, VIS1);
@@ -3889,6 +3956,7 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_op_load_fpr_DT1(DFPREG(rs2));
                     gen_helper_fmuld8ulx16();
                     gen_op_store_DT0_fpr(DFPREG(rd));
+                    gen_update_fprs_dirty(DFPREG(rd));
                     break;
                 case 0x03a: /* VIS I fpack32 */
                 case 0x03b: /* VIS I fpack16 */
@@ -3902,6 +3970,7 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_op_load_fpr_DT1(DFPREG(rs2));
                     gen_helper_faligndata();
                     gen_op_store_DT0_fpr(DFPREG(rd));
+                    gen_update_fprs_dirty(DFPREG(rd));
                     break;
                 case 0x04b: /* VIS I fpmerge */
                     CHECK_FPU_FEATURE(dc, VIS1);
@@ -3909,6 +3978,7 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_op_load_fpr_DT1(DFPREG(rs2));
                     gen_helper_fpmerge();
                     gen_op_store_DT0_fpr(DFPREG(rd));
+                    gen_update_fprs_dirty(DFPREG(rd));
                     break;
                 case 0x04c: /* VIS II bshuffle */
                     // XXX
@@ -3919,6 +3989,7 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_op_load_fpr_DT1(DFPREG(rs2));
                     gen_helper_fexpand();
                     gen_op_store_DT0_fpr(DFPREG(rd));
+                    gen_update_fprs_dirty(DFPREG(rd));
                     break;
                 case 0x050: /* VIS I fpadd16 */
                     CHECK_FPU_FEATURE(dc, VIS1);
@@ -3926,11 +3997,13 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_op_load_fpr_DT1(DFPREG(rs2));
                     gen_helper_fpadd16();
                     gen_op_store_DT0_fpr(DFPREG(rd));
+                    gen_update_fprs_dirty(DFPREG(rd));
                     break;
                 case 0x051: /* VIS I fpadd16s */
                     CHECK_FPU_FEATURE(dc, VIS1);
                     gen_helper_fpadd16s(cpu_fpr[rd],
                                         cpu_fpr[rs1], cpu_fpr[rs2]);
+                    gen_update_fprs_dirty(rd);
                     break;
                 case 0x052: /* VIS I fpadd32 */
                     CHECK_FPU_FEATURE(dc, VIS1);
@@ -3938,11 +4011,13 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_op_load_fpr_DT1(DFPREG(rs2));
                     gen_helper_fpadd32();
                     gen_op_store_DT0_fpr(DFPREG(rd));
+                    gen_update_fprs_dirty(DFPREG(rd));
                     break;
                 case 0x053: /* VIS I fpadd32s */
                     CHECK_FPU_FEATURE(dc, VIS1);
                     gen_helper_fpadd32s(cpu_fpr[rd],
                                         cpu_fpr[rs1], cpu_fpr[rs2]);
+                    gen_update_fprs_dirty(rd);
                     break;
                 case 0x054: /* VIS I fpsub16 */
                     CHECK_FPU_FEATURE(dc, VIS1);
@@ -3950,11 +4025,13 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_op_load_fpr_DT1(DFPREG(rs2));
                     gen_helper_fpsub16();
                     gen_op_store_DT0_fpr(DFPREG(rd));
+                    gen_update_fprs_dirty(DFPREG(rd));
                     break;
                 case 0x055: /* VIS I fpsub16s */
                     CHECK_FPU_FEATURE(dc, VIS1);
                     gen_helper_fpsub16s(cpu_fpr[rd],
                                         cpu_fpr[rs1], cpu_fpr[rs2]);
+                    gen_update_fprs_dirty(rd);
                     break;
                 case 0x056: /* VIS I fpsub32 */
                     CHECK_FPU_FEATURE(dc, VIS1);
@@ -3962,31 +4039,38 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_op_load_fpr_DT1(DFPREG(rs2));
                     gen_helper_fpsub32();
                     gen_op_store_DT0_fpr(DFPREG(rd));
+                    gen_update_fprs_dirty(DFPREG(rd));
                     break;
                 case 0x057: /* VIS I fpsub32s */
                     CHECK_FPU_FEATURE(dc, VIS1);
                     gen_helper_fpsub32s(cpu_fpr[rd],
                                         cpu_fpr[rs1], cpu_fpr[rs2]);
+                    gen_update_fprs_dirty(rd);
                     break;
                 case 0x060: /* VIS I fzero */
                     CHECK_FPU_FEATURE(dc, VIS1);
                     tcg_gen_movi_i32(cpu_fpr[DFPREG(rd)], 0);
                     tcg_gen_movi_i32(cpu_fpr[DFPREG(rd) + 1], 0);
+                    gen_update_fprs_dirty(DFPREG(rd));
                     break;
                 case 0x061: /* VIS I fzeros */
                     CHECK_FPU_FEATURE(dc, VIS1);
                     tcg_gen_movi_i32(cpu_fpr[rd], 0);
+                    gen_update_fprs_dirty(rd);
                     break;
                 case 0x062: /* VIS I fnor */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_nor_i32(cpu_tmp32, cpu_fpr[DFPREG(rs1)],
+                    tcg_gen_nor_i32(cpu_fpr[DFPREG(rd)], cpu_fpr[DFPREG(rs1)],
                                     cpu_fpr[DFPREG(rs2)]);
-                    tcg_gen_nor_i32(cpu_tmp32, cpu_fpr[DFPREG(rs1) + 1],
+                    tcg_gen_nor_i32(cpu_fpr[DFPREG(rd) + 1],
+                                    cpu_fpr[DFPREG(rs1) + 1],
                                     cpu_fpr[DFPREG(rs2) + 1]);
+                    gen_update_fprs_dirty(DFPREG(rd));
                     break;
                 case 0x063: /* VIS I fnors */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_nor_i32(cpu_tmp32, cpu_fpr[rs1], cpu_fpr[rs2]);
+                    tcg_gen_nor_i32(cpu_fpr[rd], cpu_fpr[rs1], cpu_fpr[rs2]);
+                    gen_update_fprs_dirty(rd);
                     break;
                 case 0x064: /* VIS I fandnot2 */
                     CHECK_FPU_FEATURE(dc, VIS1);
@@ -3995,20 +4079,24 @@ static void disas_sparc_insn(DisasContext * dc)
                     tcg_gen_andc_i32(cpu_fpr[DFPREG(rd) + 1],
                                      cpu_fpr[DFPREG(rs1) + 1],
                                      cpu_fpr[DFPREG(rs2) + 1]);
+                    gen_update_fprs_dirty(DFPREG(rd));
                     break;
                 case 0x065: /* VIS I fandnot2s */
                     CHECK_FPU_FEATURE(dc, VIS1);
                     tcg_gen_andc_i32(cpu_fpr[rd], cpu_fpr[rs1], cpu_fpr[rs2]);
+                    gen_update_fprs_dirty(rd);
                     break;
                 case 0x066: /* VIS I fnot2 */
                     CHECK_FPU_FEATURE(dc, VIS1);
                     tcg_gen_not_i32(cpu_fpr[DFPREG(rd)], cpu_fpr[DFPREG(rs2)]);
                     tcg_gen_not_i32(cpu_fpr[DFPREG(rd) + 1],
                                     cpu_fpr[DFPREG(rs2) + 1]);
+                    gen_update_fprs_dirty(DFPREG(rd));
                     break;
                 case 0x067: /* VIS I fnot2s */
                     CHECK_FPU_FEATURE(dc, VIS1);
                     tcg_gen_not_i32(cpu_fpr[rd], cpu_fpr[rs2]);
+                    gen_update_fprs_dirty(rd);
                     break;
                 case 0x068: /* VIS I fandnot1 */
                     CHECK_FPU_FEATURE(dc, VIS1);
@@ -4017,20 +4105,24 @@ static void disas_sparc_insn(DisasContext * dc)
                     tcg_gen_andc_i32(cpu_fpr[DFPREG(rd) + 1],
                                      cpu_fpr[DFPREG(rs2) + 1],
                                      cpu_fpr[DFPREG(rs1) + 1]);
+                    gen_update_fprs_dirty(DFPREG(rd));
                     break;
                 case 0x069: /* VIS I fandnot1s */
                     CHECK_FPU_FEATURE(dc, VIS1);
                     tcg_gen_andc_i32(cpu_fpr[rd], cpu_fpr[rs2], cpu_fpr[rs1]);
+                    gen_update_fprs_dirty(rd);
                     break;
                 case 0x06a: /* VIS I fnot1 */
                     CHECK_FPU_FEATURE(dc, VIS1);
                     tcg_gen_not_i32(cpu_fpr[DFPREG(rd)], cpu_fpr[DFPREG(rs1)]);
                     tcg_gen_not_i32(cpu_fpr[DFPREG(rd) + 1],
                                     cpu_fpr[DFPREG(rs1) + 1]);
+                    gen_update_fprs_dirty(DFPREG(rd));
                     break;
                 case 0x06b: /* VIS I fnot1s */
                     CHECK_FPU_FEATURE(dc, VIS1);
                     tcg_gen_not_i32(cpu_fpr[rd], cpu_fpr[rs1]);
+                    gen_update_fprs_dirty(rd);
                     break;
                 case 0x06c: /* VIS I fxor */
                     CHECK_FPU_FEATURE(dc, VIS1);
@@ -4039,21 +4131,26 @@ static void disas_sparc_insn(DisasContext * dc)
                     tcg_gen_xor_i32(cpu_fpr[DFPREG(rd) + 1],
                                     cpu_fpr[DFPREG(rs1) + 1],
                                     cpu_fpr[DFPREG(rs2) + 1]);
+                    gen_update_fprs_dirty(DFPREG(rd));
                     break;
                 case 0x06d: /* VIS I fxors */
                     CHECK_FPU_FEATURE(dc, VIS1);
                     tcg_gen_xor_i32(cpu_fpr[rd], cpu_fpr[rs1], cpu_fpr[rs2]);
+                    gen_update_fprs_dirty(rd);
                     break;
                 case 0x06e: /* VIS I fnand */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_nand_i32(cpu_tmp32, cpu_fpr[DFPREG(rs1)],
+                    tcg_gen_nand_i32(cpu_fpr[DFPREG(rd)], cpu_fpr[DFPREG(rs1)],
                                      cpu_fpr[DFPREG(rs2)]);
-                    tcg_gen_nand_i32(cpu_tmp32, cpu_fpr[DFPREG(rs1) + 1],
+                    tcg_gen_nand_i32(cpu_fpr[DFPREG(rd) + 1],
+                                     cpu_fpr[DFPREG(rs1) + 1],
                                      cpu_fpr[DFPREG(rs2) + 1]);
+                    gen_update_fprs_dirty(DFPREG(rd));
                     break;
                 case 0x06f: /* VIS I fnands */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_nand_i32(cpu_tmp32, cpu_fpr[rs1], cpu_fpr[rs2]);
+                    tcg_gen_nand_i32(cpu_fpr[rd], cpu_fpr[rs1], cpu_fpr[rs2]);
+                    gen_update_fprs_dirty(rd);
                     break;
                 case 0x070: /* VIS I fand */
                     CHECK_FPU_FEATURE(dc, VIS1);
@@ -4062,10 +4159,12 @@ static void disas_sparc_insn(DisasContext * dc)
                     tcg_gen_and_i32(cpu_fpr[DFPREG(rd) + 1],
                                     cpu_fpr[DFPREG(rs1) + 1],
                                     cpu_fpr[DFPREG(rs2) + 1]);
+                    gen_update_fprs_dirty(DFPREG(rd));
                     break;
                 case 0x071: /* VIS I fands */
                     CHECK_FPU_FEATURE(dc, VIS1);
                     tcg_gen_and_i32(cpu_fpr[rd], cpu_fpr[rs1], cpu_fpr[rs2]);
+                    gen_update_fprs_dirty(rd);
                     break;
                 case 0x072: /* VIS I fxnor */
                     CHECK_FPU_FEATURE(dc, VIS1);
@@ -4075,21 +4174,25 @@ static void disas_sparc_insn(DisasContext * dc)
                     tcg_gen_xori_i32(cpu_tmp32, cpu_fpr[DFPREG(rs2) + 1], -1);
                     tcg_gen_xor_i32(cpu_fpr[DFPREG(rd) + 1], cpu_tmp32,
                                     cpu_fpr[DFPREG(rs1) + 1]);
+                    gen_update_fprs_dirty(DFPREG(rd));
                     break;
                 case 0x073: /* VIS I fxnors */
                     CHECK_FPU_FEATURE(dc, VIS1);
                     tcg_gen_xori_i32(cpu_tmp32, cpu_fpr[rs2], -1);
                     tcg_gen_xor_i32(cpu_fpr[rd], cpu_tmp32, cpu_fpr[rs1]);
+                    gen_update_fprs_dirty(rd);
                     break;
                 case 0x074: /* VIS I fsrc1 */
                     CHECK_FPU_FEATURE(dc, VIS1);
                     tcg_gen_mov_i32(cpu_fpr[DFPREG(rd)], cpu_fpr[DFPREG(rs1)]);
                     tcg_gen_mov_i32(cpu_fpr[DFPREG(rd) + 1],
                                     cpu_fpr[DFPREG(rs1) + 1]);
+                    gen_update_fprs_dirty(DFPREG(rd));
                     break;
                 case 0x075: /* VIS I fsrc1s */
                     CHECK_FPU_FEATURE(dc, VIS1);
                     tcg_gen_mov_i32(cpu_fpr[rd], cpu_fpr[rs1]);
+                    gen_update_fprs_dirty(rd);
                     break;
                 case 0x076: /* VIS I fornot2 */
                     CHECK_FPU_FEATURE(dc, VIS1);
@@ -4098,19 +4201,23 @@ static void disas_sparc_insn(DisasContext * dc)
                     tcg_gen_orc_i32(cpu_fpr[DFPREG(rd) + 1],
                                     cpu_fpr[DFPREG(rs1) + 1],
                                     cpu_fpr[DFPREG(rs2) + 1]);
+                    gen_update_fprs_dirty(DFPREG(rd));
                     break;
                 case 0x077: /* VIS I fornot2s */
                     CHECK_FPU_FEATURE(dc, VIS1);
                     tcg_gen_orc_i32(cpu_fpr[rd], cpu_fpr[rs1], cpu_fpr[rs2]);
+                    gen_update_fprs_dirty(rd);
                     break;
                 case 0x078: /* VIS I fsrc2 */
                     CHECK_FPU_FEATURE(dc, VIS1);
                     gen_op_load_fpr_DT0(DFPREG(rs2));
                     gen_op_store_DT0_fpr(DFPREG(rd));
+                    gen_update_fprs_dirty(DFPREG(rd));
                     break;
                 case 0x079: /* VIS I fsrc2s */
                     CHECK_FPU_FEATURE(dc, VIS1);
                     tcg_gen_mov_i32(cpu_fpr[rd], cpu_fpr[rs2]);
+                    gen_update_fprs_dirty(rd);
                     break;
                 case 0x07a: /* VIS I fornot1 */
                     CHECK_FPU_FEATURE(dc, VIS1);
@@ -4119,10 +4226,12 @@ static void disas_sparc_insn(DisasContext * dc)
                     tcg_gen_orc_i32(cpu_fpr[DFPREG(rd) + 1],
                                     cpu_fpr[DFPREG(rs2) + 1],
                                     cpu_fpr[DFPREG(rs1) + 1]);
+                    gen_update_fprs_dirty(DFPREG(rd));
                     break;
                 case 0x07b: /* VIS I fornot1s */
                     CHECK_FPU_FEATURE(dc, VIS1);
                     tcg_gen_orc_i32(cpu_fpr[rd], cpu_fpr[rs2], cpu_fpr[rs1]);
+                    gen_update_fprs_dirty(rd);
                     break;
                 case 0x07c: /* VIS I for */
                     CHECK_FPU_FEATURE(dc, VIS1);
@@ -4131,19 +4240,23 @@ static void disas_sparc_insn(DisasContext * dc)
                     tcg_gen_or_i32(cpu_fpr[DFPREG(rd) + 1],
                                    cpu_fpr[DFPREG(rs1) + 1],
                                    cpu_fpr[DFPREG(rs2) + 1]);
+                    gen_update_fprs_dirty(DFPREG(rd));
                     break;
                 case 0x07d: /* VIS I fors */
                     CHECK_FPU_FEATURE(dc, VIS1);
                     tcg_gen_or_i32(cpu_fpr[rd], cpu_fpr[rs1], cpu_fpr[rs2]);
+                    gen_update_fprs_dirty(rd);
                     break;
                 case 0x07e: /* VIS I fone */
                     CHECK_FPU_FEATURE(dc, VIS1);
                     tcg_gen_movi_i32(cpu_fpr[DFPREG(rd)], -1);
                     tcg_gen_movi_i32(cpu_fpr[DFPREG(rd) + 1], -1);
+                    gen_update_fprs_dirty(DFPREG(rd));
                     break;
                 case 0x07f: /* VIS I fones */
                     CHECK_FPU_FEATURE(dc, VIS1);
                     tcg_gen_movi_i32(cpu_fpr[rd], -1);
+                    gen_update_fprs_dirty(rd);
                     break;
                 case 0x080: /* VIS I shutdown */
                 case 0x081: /* VIS II siam */
@@ -4489,6 +4602,7 @@ static void disas_sparc_insn(DisasContext * dc)
                     }
                     save_state(dc, cpu_cond);
                     gen_ldf_asi(cpu_addr, insn, 4, rd);
+                    gen_update_fprs_dirty(rd);
                     goto skip_move;
                 case 0x33: /* V9 lddfa */
                     if (gen_trap_ifnofpu(dc, cpu_cond)) {
@@ -4496,6 +4610,7 @@ static void disas_sparc_insn(DisasContext * dc)
                     }
                     save_state(dc, cpu_cond);
                     gen_ldf_asi(cpu_addr, insn, 8, DFPREG(rd));
+                    gen_update_fprs_dirty(DFPREG(rd));
                     goto skip_move;
                 case 0x3d: /* V9 prefetcha, no effect */
                     goto skip_move;
@@ -4506,6 +4621,7 @@ static void disas_sparc_insn(DisasContext * dc)
                     }
                     save_state(dc, cpu_cond);
                     gen_ldf_asi(cpu_addr, insn, 16, QFPREG(rd));
+                    gen_update_fprs_dirty(QFPREG(rd));
                     goto skip_move;
 #endif
                 default:
@@ -4524,6 +4640,7 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_address_mask(dc, cpu_addr);
                     tcg_gen_qemu_ld32u(cpu_tmp0, cpu_addr, dc->mem_idx);
                     tcg_gen_trunc_tl_i32(cpu_fpr[rd], cpu_tmp0);
+                    gen_update_fprs_dirty(rd);
                     break;
                 case 0x21:      /* ldfsr, V9 ldxfsr */
 #ifdef TARGET_SPARC64
@@ -4553,6 +4670,7 @@ static void disas_sparc_insn(DisasContext * dc)
                         gen_helper_ldqf(cpu_addr, r_const);
                         tcg_temp_free_i32(r_const);
                         gen_op_store_QT0_fpr(QFPREG(rd));
+                        gen_update_fprs_dirty(QFPREG(rd));
                     }
                     break;
                 case 0x23:      /* lddf, load double fpreg */
@@ -4564,6 +4682,7 @@ static void disas_sparc_insn(DisasContext * dc)
                         gen_helper_lddf(cpu_addr, r_const);
                         tcg_temp_free_i32(r_const);
                         gen_op_store_DT0_fpr(DFPREG(rd));
+                        gen_update_fprs_dirty(DFPREG(rd));
                     }
                     break;
                 default: