summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--target-sparc/asi.h311
-rw-r--r--target-sparc/cpu.h28
-rw-r--r--target-sparc/fop_helper.c230
-rw-r--r--target-sparc/helper.h168
-rw-r--r--target-sparc/ldst_helper.c696
-rw-r--r--target-sparc/translate.c1273
6 files changed, 1607 insertions, 1099 deletions
diff --git a/target-sparc/asi.h b/target-sparc/asi.h
new file mode 100644
index 0000000000..c9a1849600
--- /dev/null
+++ b/target-sparc/asi.h
@@ -0,0 +1,311 @@
+#ifndef _SPARC_ASI_H
+#define _SPARC_ASI_H
+
+/* asi.h:  Address Space Identifier values for the sparc.
+ *
+ * Copyright (C) 1995,1996 David S. Miller (davem@caip.rutgers.edu)
+ *
+ * Pioneer work for sun4m: Paul Hatchman (paul@sfe.com.au)
+ * Joint edition for sun4c+sun4m: Pete A. Zaitcev <zaitcev@ipmce.su>
+ */
+
+/* The first batch are for the sun4c. */
+
+#define ASI_NULL1           0x00
+#define ASI_NULL2           0x01
+
+/* sun4c and sun4 control registers and mmu/vac ops */
+#define ASI_CONTROL         0x02
+#define ASI_SEGMAP          0x03
+#define ASI_PTE             0x04
+#define ASI_HWFLUSHSEG      0x05
+#define ASI_HWFLUSHPAGE     0x06
+#define ASI_REGMAP          0x06
+#define ASI_HWFLUSHCONTEXT  0x07
+
+#define ASI_USERTXT         0x08
+#define ASI_KERNELTXT       0x09
+#define ASI_USERDATA        0x0a
+#define ASI_KERNELDATA      0x0b
+
+/* VAC Cache flushing on sun4c and sun4 */
+#define ASI_FLUSHSEG        0x0c
+#define ASI_FLUSHPG         0x0d
+#define ASI_FLUSHCTX        0x0e
+
+/* SPARCstation-5: only 6 bits are decoded. */
+/* wo = Write Only, rw = Read Write;        */
+/* ss = Single Size, as = All Sizes;        */
+#define ASI_M_RES00         0x00   /* Don't touch... */
+#define ASI_M_UNA01         0x01   /* Same here... */
+#define ASI_M_MXCC          0x02   /* Access to TI VIKING MXCC registers */
+#define ASI_M_FLUSH_PROBE   0x03   /* Reference MMU Flush/Probe; rw, ss */
+#define ASI_M_MMUREGS       0x04   /* MMU Registers; rw, ss */
+#define ASI_M_TLBDIAG       0x05   /* MMU TLB only Diagnostics */
+#define ASI_M_DIAGS         0x06   /* Reference MMU Diagnostics */
+#define ASI_M_IODIAG        0x07   /* MMU I/O TLB only Diagnostics */
+#define ASI_M_USERTXT       0x08   /* Same as ASI_USERTXT; rw, as */
+#define ASI_M_KERNELTXT     0x09   /* Same as ASI_KERNELTXT; rw, as */
+#define ASI_M_USERDATA      0x0A   /* Same as ASI_USERDATA; rw, as */
+#define ASI_M_KERNELDATA    0x0B   /* Same as ASI_KERNELDATA; rw, as */
+#define ASI_M_TXTC_TAG      0x0C   /* Instruction Cache Tag; rw, ss */
+#define ASI_M_TXTC_DATA     0x0D   /* Instruction Cache Data; rw, ss */
+#define ASI_M_DATAC_TAG     0x0E   /* Data Cache Tag; rw, ss */
+#define ASI_M_DATAC_DATA    0x0F   /* Data Cache Data; rw, ss */
+
+/* The following cache flushing ASIs work only with the 'sta'
+ * instruction. Results are unpredictable for 'swap' and 'ldstuba',
+ * so don't do it.
+ */
+
+/* These ASI flushes affect external caches too. */
+#define ASI_M_FLUSH_PAGE    0x10   /* Flush I&D Cache Line (page); wo, ss */
+#define ASI_M_FLUSH_SEG     0x11   /* Flush I&D Cache Line (seg); wo, ss */
+#define ASI_M_FLUSH_REGION  0x12   /* Flush I&D Cache Line (region); wo, ss */
+#define ASI_M_FLUSH_CTX     0x13   /* Flush I&D Cache Line (context); wo, ss */
+#define ASI_M_FLUSH_USER    0x14   /* Flush I&D Cache Line (user); wo, ss */
+
+/* Block-copy operations are available only on certain V8 cpus. */
+#define ASI_M_BCOPY         0x17   /* Block copy */
+
+/* These affect only the ICACHE and are Ross HyperSparc and TurboSparc specific. */
+#define ASI_M_IFLUSH_PAGE   0x18   /* Flush I Cache Line (page); wo, ss */
+#define ASI_M_IFLUSH_SEG    0x19   /* Flush I Cache Line (seg); wo, ss */
+#define ASI_M_IFLUSH_REGION 0x1A   /* Flush I Cache Line (region); wo, ss */
+#define ASI_M_IFLUSH_CTX    0x1B   /* Flush I Cache Line (context); wo, ss */
+#define ASI_M_IFLUSH_USER   0x1C   /* Flush I Cache Line (user); wo, ss */
+
+/* Block-fill operations are available on certain V8 cpus */
+#define ASI_M_BFILL         0x1F
+
+/* This allows direct access to main memory, actually 0x20 to 0x2f are
+ * the available ASI's for physical ram pass-through, but I don't have
+ * any idea what the other ones do....
+ */
+
+#define ASI_M_BYPASS       0x20   /* Reference MMU bypass; rw, as */
+#define ASI_M_FBMEM        0x29   /* Graphics card frame buffer access */
+#define ASI_M_VMEUS        0x2A   /* VME user 16-bit access */
+#define ASI_M_VMEPS        0x2B   /* VME priv 16-bit access */
+#define ASI_M_VMEUT        0x2C   /* VME user 32-bit access */
+#define ASI_M_VMEPT        0x2D   /* VME priv 32-bit access */
+#define ASI_M_SBUS         0x2E   /* Direct SBus access */
+#define ASI_M_CTL          0x2F   /* Control Space (ECC and MXCC are here) */
+
+
+/* This is ROSS HyperSparc only. */
+#define ASI_M_FLUSH_IWHOLE 0x31   /* Flush entire ICACHE; wo, ss */
+
+/* Tsunami/Viking/TurboSparc i/d cache flash clear. */
+#define ASI_M_IC_FLCLEAR   0x36
+#define ASI_M_DC_FLCLEAR   0x37
+
+#define ASI_M_DCDR         0x39   /* Data Cache Diagnostics Register rw, ss */
+
+#define ASI_M_VIKING_TMP1  0x40	  /* Emulation temporary 1 on Viking */
+/* only available on SuperSparc I */
+/* #define ASI_M_VIKING_TMP2  0x41 */  /* Emulation temporary 2 on Viking */
+
+#define ASI_M_ACTION       0x4c   /* Breakpoint Action Register (GNU/Viking) */
+
+/* LEON ASI */
+#define ASI_LEON_NOCACHE        0x01
+
+#define ASI_LEON_DCACHE_MISS    0x01
+
+#define ASI_LEON_CACHEREGS      0x02
+#define ASI_LEON_IFLUSH         0x10
+#define ASI_LEON_DFLUSH         0x11
+
+#define ASI_LEON_MMUFLUSH       0x18
+#define ASI_LEON_MMUREGS        0x19
+#define ASI_LEON_BYPASS         0x1c
+#define ASI_LEON_FLUSH_PAGE     0x10
+
+/* V9 Architecture mandary ASIs. */
+#define ASI_N			0x04 /* Nucleus				*/
+#define ASI_NL			0x0c /* Nucleus, little endian		*/
+#define ASI_AIUP		0x10 /* Primary, user			*/
+#define ASI_AIUS		0x11 /* Secondary, user			*/
+#define ASI_AIUPL		0x18 /* Primary, user, little endian	*/
+#define ASI_AIUSL		0x19 /* Secondary, user, little endian	*/
+#define ASI_P			0x80 /* Primary, implicit		*/
+#define ASI_S			0x81 /* Secondary, implicit		*/
+#define ASI_PNF			0x82 /* Primary, no fault		*/
+#define ASI_SNF			0x83 /* Secondary, no fault		*/
+#define ASI_PL			0x88 /* Primary, implicit, l-endian	*/
+#define ASI_SL			0x89 /* Secondary, implicit, l-endian	*/
+#define ASI_PNFL		0x8a /* Primary, no fault, l-endian	*/
+#define ASI_SNFL		0x8b /* Secondary, no fault, l-endian	*/
+
+/* SpitFire and later extended ASIs.  The "(III)" marker designates
+ * UltraSparc-III and later specific ASIs.  The "(CMT)" marker designates
+ * Chip Multi Threading specific ASIs.  "(NG)" designates Niagara specific
+ * ASIs, "(4V)" designates SUN4V specific ASIs.  "(NG4)" designates SPARC-T4
+ * and later ASIs.
+ */
+#define ASI_REAL                0x14 /* Real address, cachable          */
+#define ASI_PHYS_USE_EC		0x14 /* PADDR, E-cachable		*/
+#define ASI_REAL_IO             0x15 /* Real address, non-cachable      */
+#define ASI_PHYS_BYPASS_EC_E	0x15 /* PADDR, E-bit			*/
+#define ASI_BLK_AIUP_4V		0x16 /* (4V) Prim, user, block ld/st	*/
+#define ASI_BLK_AIUS_4V		0x17 /* (4V) Sec, user, block ld/st	*/
+#define ASI_REAL_L              0x1c /* Real address, cachable, LE      */
+#define ASI_PHYS_USE_EC_L	0x1c /* PADDR, E-cachable, little endian*/
+#define ASI_REAL_IO_L           0x1d /* Real address, non-cachable, LE  */
+#define ASI_PHYS_BYPASS_EC_E_L	0x1d /* PADDR, E-bit, little endian	*/
+#define ASI_BLK_AIUP_L_4V	0x1e /* (4V) Prim, user, block, l-endian*/
+#define ASI_BLK_AIUS_L_4V	0x1f /* (4V) Sec, user, block, l-endian	*/
+#define ASI_SCRATCHPAD		0x20 /* (4V) Scratch Pad Registers	*/
+#define ASI_MMU			0x21 /* (4V) MMU Context Registers	*/
+#define ASI_TWINX_AIUP          0x22 /* twin load, primary user         */
+#define ASI_TWINX_AIUS          0x23 /* twin load, secondary user       */
+#define ASI_BLK_INIT_QUAD_LDD_AIUS 0x23 /* (NG) init-store, twin load,
+					 * secondary, user
+					 */
+#define ASI_NUCLEUS_QUAD_LDD	0x24 /* Cachable, qword load		*/
+#define ASI_QUEUE		0x25 /* (4V) Interrupt Queue Registers	*/
+#define ASI_TWINX_REAL          0x26 /* twin load, real, cachable       */
+#define ASI_QUAD_LDD_PHYS_4V	0x26 /* (4V) Physical, qword load	*/
+#define ASI_TWINX_N             0x27 /* twin load, nucleus              */
+#define ASI_TWINX_AIUP_L        0x2a /* twin load, primary user, LE     */
+#define ASI_TWINX_AIUS_L        0x2b /* twin load, secondary user, LE   */
+#define ASI_NUCLEUS_QUAD_LDD_L	0x2c /* Cachable, qword load, l-endian 	*/
+#define ASI_TWINX_REAL_L        0x2e /* twin load, real, cachable, LE   */
+#define ASI_QUAD_LDD_PHYS_L_4V	0x2e /* (4V) Phys, qword load, l-endian	*/
+#define ASI_TWINX_NL            0x2f /* twin load, nucleus, LE          */
+#define ASI_PCACHE_DATA_STATUS	0x30 /* (III) PCache data stat RAM diag	*/
+#define ASI_PCACHE_DATA		0x31 /* (III) PCache data RAM diag	*/
+#define ASI_PCACHE_TAG		0x32 /* (III) PCache tag RAM diag	*/
+#define ASI_PCACHE_SNOOP_TAG	0x33 /* (III) PCache snoop tag RAM diag	*/
+#define ASI_QUAD_LDD_PHYS	0x34 /* (III+) PADDR, qword load	*/
+#define ASI_WCACHE_VALID_BITS	0x38 /* (III) WCache Valid Bits diag	*/
+#define ASI_WCACHE_DATA		0x39 /* (III) WCache data RAM diag	*/
+#define ASI_WCACHE_TAG		0x3a /* (III) WCache tag RAM diag	*/
+#define ASI_WCACHE_SNOOP_TAG	0x3b /* (III) WCache snoop tag RAM diag	*/
+#define ASI_QUAD_LDD_PHYS_L	0x3c /* (III+) PADDR, qw-load, l-endian	*/
+#define ASI_SRAM_FAST_INIT	0x40 /* (III+) Fast SRAM init		*/
+#define ASI_CORE_AVAILABLE	0x41 /* (CMT) LP Available		*/
+#define ASI_CORE_ENABLE_STAT	0x41 /* (CMT) LP Enable Status		*/
+#define ASI_CORE_ENABLE		0x41 /* (CMT) LP Enable RW		*/
+#define ASI_XIR_STEERING	0x41 /* (CMT) XIR Steering RW		*/
+#define ASI_CORE_RUNNING_RW	0x41 /* (CMT) LP Running RW		*/
+#define ASI_CORE_RUNNING_W1S	0x41 /* (CMT) LP Running Write-One Set	*/
+#define ASI_CORE_RUNNING_W1C	0x41 /* (CMT) LP Running Write-One Clr	*/
+#define ASI_CORE_RUNNING_STAT	0x41 /* (CMT) LP Running Status		*/
+#define ASI_CMT_ERROR_STEERING	0x41 /* (CMT) Error Steering RW		*/
+#define ASI_DCACHE_INVALIDATE	0x42 /* (III) DCache Invalidate diag	*/
+#define ASI_DCACHE_UTAG		0x43 /* (III) DCache uTag diag		*/
+#define ASI_DCACHE_SNOOP_TAG	0x44 /* (III) DCache snoop tag RAM diag	*/
+#define ASI_LSU_CONTROL		0x45 /* Load-store control unit		*/
+#define ASI_DCU_CONTROL_REG	0x45 /* (III) DCache Unit Control reg	*/
+#define ASI_DCACHE_DATA		0x46 /* DCache data-ram diag access	*/
+#define ASI_DCACHE_TAG		0x47 /* Dcache tag/valid ram diag access*/
+#define ASI_INTR_DISPATCH_STAT	0x48 /* IRQ vector dispatch status	*/
+#define ASI_INTR_RECEIVE	0x49 /* IRQ vector receive status	*/
+#define ASI_UPA_CONFIG		0x4a /* UPA config space		*/
+#define ASI_JBUS_CONFIG		0x4a /* (IIIi) JBUS Config Register	*/
+#define ASI_SAFARI_CONFIG	0x4a /* (III) Safari Config Register	*/
+#define ASI_SAFARI_ADDRESS	0x4a /* (III) Safari Address Register	*/
+#define ASI_ESTATE_ERROR_EN	0x4b /* E-cache error enable space	*/
+#define ASI_AFSR		0x4c /* Async fault status register	*/
+#define ASI_AFAR		0x4d /* Async fault address register	*/
+#define ASI_EC_TAG_DATA		0x4e /* E-cache tag/valid ram diag acc	*/
+#define ASI_IMMU		0x50 /* Insn-MMU main register space	*/
+#define ASI_IMMU_TSB_8KB_PTR	0x51 /* Insn-MMU 8KB TSB pointer reg	*/
+#define ASI_IMMU_TSB_64KB_PTR	0x52 /* Insn-MMU 64KB TSB pointer reg	*/
+#define ASI_ITLB_DATA_IN	0x54 /* Insn-MMU TLB data in reg	*/
+#define ASI_ITLB_DATA_ACCESS	0x55 /* Insn-MMU TLB data access reg	*/
+#define ASI_ITLB_TAG_READ	0x56 /* Insn-MMU TLB tag read reg	*/
+#define ASI_IMMU_DEMAP		0x57 /* Insn-MMU TLB demap		*/
+#define ASI_DMMU		0x58 /* Data-MMU main register space	*/
+#define ASI_DMMU_TSB_8KB_PTR	0x59 /* Data-MMU 8KB TSB pointer reg	*/
+#define ASI_DMMU_TSB_64KB_PTR	0x5a /* Data-MMU 16KB TSB pointer reg	*/
+#define ASI_DMMU_TSB_DIRECT_PTR	0x5b /* Data-MMU TSB direct pointer reg	*/
+#define ASI_DTLB_DATA_IN	0x5c /* Data-MMU TLB data in reg	*/
+#define ASI_DTLB_DATA_ACCESS	0x5d /* Data-MMU TLB data access reg	*/
+#define ASI_DTLB_TAG_READ	0x5e /* Data-MMU TLB tag read reg	*/
+#define ASI_DMMU_DEMAP		0x5f /* Data-MMU TLB demap		*/
+#define ASI_IIU_INST_TRAP	0x60 /* (III) Instruction Breakpoint	*/
+#define ASI_INTR_ID		0x63 /* (CMT) Interrupt ID register	*/
+#define ASI_CORE_ID		0x63 /* (CMT) LP ID register		*/
+#define ASI_CESR_ID		0x63 /* (CMT) CESR ID register		*/
+#define ASI_IC_INSTR		0x66 /* Insn cache instrucion ram diag	*/
+#define ASI_IC_TAG		0x67 /* Insn cache tag/valid ram diag 	*/
+#define ASI_IC_STAG		0x68 /* (III) Insn cache snoop tag ram	*/
+#define ASI_IC_PRE_DECODE	0x6e /* Insn cache pre-decode ram diag	*/
+#define ASI_IC_NEXT_FIELD	0x6f /* Insn cache next-field ram diag	*/
+#define ASI_BRPRED_ARRAY	0x6f /* (III) Branch Prediction RAM diag*/
+#define ASI_BLK_AIUP		0x70 /* Primary, user, block load/store	*/
+#define ASI_BLK_AIUS		0x71 /* Secondary, user, block ld/st	*/
+#define ASI_MCU_CTRL_REG	0x72 /* (III) Memory controller regs	*/
+#define ASI_EC_DATA		0x74 /* (III) E-cache data staging reg	*/
+#define ASI_EC_CTRL		0x75 /* (III) E-cache control reg	*/
+#define ASI_EC_W		0x76 /* E-cache diag write access	*/
+#define ASI_UDB_ERROR_W		0x77 /* External UDB error regs W	*/
+#define ASI_UDB_CONTROL_W	0x77 /* External UDB control regs W	*/
+#define ASI_INTR_W		0x77 /* IRQ vector dispatch write	*/
+#define ASI_INTR_DATAN_W	0x77 /* (III) Out irq vector data reg N	*/
+#define ASI_INTR_DISPATCH_W	0x77 /* (III) Interrupt vector dispatch	*/
+#define ASI_BLK_AIUPL		0x78 /* Primary, user, little, blk ld/st*/
+#define ASI_BLK_AIUSL		0x79 /* Secondary, user, little, blk ld/st*/
+#define ASI_EC_R		0x7e /* E-cache diag read access	*/
+#define ASI_UDBH_ERROR_R	0x7f /* External UDB error regs rd hi	*/
+#define ASI_UDBL_ERROR_R	0x7f /* External UDB error regs rd low	*/
+#define ASI_UDBH_CONTROL_R	0x7f /* External UDB control regs rd hi	*/
+#define ASI_UDBL_CONTROL_R	0x7f /* External UDB control regs rd low*/
+#define ASI_INTR_R		0x7f /* IRQ vector dispatch read	*/
+#define ASI_INTR_DATAN_R	0x7f /* (III) In irq vector data reg N	*/
+#define ASI_PIC			0xb0 /* (NG4) PIC registers		*/
+#define ASI_PST8_P		0xc0 /* Primary, 8 8-bit, partial	*/
+#define ASI_PST8_S		0xc1 /* Secondary, 8 8-bit, partial	*/
+#define ASI_PST16_P		0xc2 /* Primary, 4 16-bit, partial	*/
+#define ASI_PST16_S		0xc3 /* Secondary, 4 16-bit, partial	*/
+#define ASI_PST32_P		0xc4 /* Primary, 2 32-bit, partial	*/
+#define ASI_PST32_S		0xc5 /* Secondary, 2 32-bit, partial	*/
+#define ASI_PST8_PL		0xc8 /* Primary, 8 8-bit, partial, L	*/
+#define ASI_PST8_SL		0xc9 /* Secondary, 8 8-bit, partial, L	*/
+#define ASI_PST16_PL		0xca /* Primary, 4 16-bit, partial, L	*/
+#define ASI_PST16_SL		0xcb /* Secondary, 4 16-bit, partial, L	*/
+#define ASI_PST32_PL		0xcc /* Primary, 2 32-bit, partial, L	*/
+#define ASI_PST32_SL		0xcd /* Secondary, 2 32-bit, partial, L	*/
+#define ASI_FL8_P		0xd0 /* Primary, 1 8-bit, fpu ld/st	*/
+#define ASI_FL8_S		0xd1 /* Secondary, 1 8-bit, fpu ld/st	*/
+#define ASI_FL16_P		0xd2 /* Primary, 1 16-bit, fpu ld/st	*/
+#define ASI_FL16_S		0xd3 /* Secondary, 1 16-bit, fpu ld/st	*/
+#define ASI_FL8_PL		0xd8 /* Primary, 1 8-bit, fpu ld/st, L	*/
+#define ASI_FL8_SL		0xd9 /* Secondary, 1 8-bit, fpu ld/st, L*/
+#define ASI_FL16_PL		0xda /* Primary, 1 16-bit, fpu ld/st, L	*/
+#define ASI_FL16_SL		0xdb /* Secondary, 1 16-bit, fpu ld/st,L*/
+#define ASI_BLK_COMMIT_P	0xe0 /* Primary, blk store commit	*/
+#define ASI_BLK_COMMIT_S	0xe1 /* Secondary, blk store commit	*/
+#define ASI_TWINX_P             0xe2 /* twin load, primary implicit     */
+#define ASI_BLK_INIT_QUAD_LDD_P	0xe2 /* (NG) init-store, twin load,
+				      * primary, implicit */
+#define ASI_TWINX_S             0xe3 /* twin load, secondary implicit   */
+#define ASI_BLK_INIT_QUAD_LDD_S	0xe3 /* (NG) init-store, twin load,
+				      * secondary, implicit */
+#define ASI_TWINX_PL            0xea /* twin load, primary implicit, LE */
+#define ASI_TWINX_SL            0xeb /* twin load, secondary implicit, LE */
+#define ASI_BLK_P		0xf0 /* Primary, blk ld/st		*/
+#define ASI_BLK_S		0xf1 /* Secondary, blk ld/st		*/
+#define ASI_ST_BLKINIT_MRU_P	0xf2 /* (NG4) init-store, twin load,
+				      * Most-Recently-Used, primary,
+				      * implicit
+				      */
+#define ASI_ST_BLKINIT_MRU_S	0xf2 /* (NG4) init-store, twin load,
+				      * Most-Recently-Used, secondary,
+				      * implicit
+				      */
+#define ASI_BLK_PL		0xf8 /* Primary, blk ld/st, little	*/
+#define ASI_BLK_SL		0xf9 /* Secondary, blk ld/st, little	*/
+#define ASI_ST_BLKINIT_MRU_PL	0xfa /* (NG4) init-store, twin load,
+				      * Most-Recently-Used, primary,
+				      * implicit, little-endian
+				      */
+#define ASI_ST_BLKINIT_MRU_SL	0xfb /* (NG4) init-store, twin load,
+				      * Most-Recently-Used, secondary,
+				      * implicit, little-endian
+				      */
+
+#endif /* _SPARC_ASI_H */
diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h
index 15364a00f2..a3d64a4e52 100644
--- a/target-sparc/cpu.h
+++ b/target-sparc/cpu.h
@@ -719,34 +719,34 @@ void cpu_tick_set_limit(CPUTimer *timer, uint64_t limit);
 trap_state* cpu_tsptr(CPUSPARCState* env);
 #endif
 
-#define TB_FLAG_FPU_ENABLED (1 << 4)
-#define TB_FLAG_AM_ENABLED (1 << 5)
+#define TB_FLAG_MMU_MASK     7
+#define TB_FLAG_FPU_ENABLED  (1 << 4)
+#define TB_FLAG_AM_ENABLED   (1 << 5)
+#define TB_FLAG_ASI_SHIFT    24
 
 static inline void cpu_get_tb_cpu_state(CPUSPARCState *env, target_ulong *pc,
-                                        target_ulong *cs_base, uint32_t *flags)
+                                        target_ulong *cs_base, uint32_t *pflags)
 {
+    uint32_t flags;
     *pc = env->pc;
     *cs_base = env->npc;
+    flags = cpu_mmu_index(env, false);
 #ifdef TARGET_SPARC64
-    // AM . Combined FPU enable bits . PRIV . DMMU enabled . IMMU enabled
-    *flags = (env->pstate & PS_PRIV)               /* 2 */
-        | ((env->lsu & (DMMU_E | IMMU_E)) >> 2)    /* 1, 0 */
-        | ((env->tl & 0xff) << 8)
-        | (env->dmmu.mmu_primary_context << 16);   /* 16... */
     if (env->pstate & PS_AM) {
-        *flags |= TB_FLAG_AM_ENABLED;
+        flags |= TB_FLAG_AM_ENABLED;
     }
-    if ((env->def->features & CPU_FEATURE_FLOAT) && (env->pstate & PS_PEF)
+    if ((env->def->features & CPU_FEATURE_FLOAT)
+        && (env->pstate & PS_PEF)
         && (env->fprs & FPRS_FEF)) {
-        *flags |= TB_FLAG_FPU_ENABLED;
+        flags |= TB_FLAG_FPU_ENABLED;
     }
+    flags |= env->asi << TB_FLAG_ASI_SHIFT;
 #else
-    // FPU enable . Supervisor
-    *flags = env->psrs;
     if ((env->def->features & CPU_FEATURE_FLOAT) && env->psref) {
-        *flags |= TB_FLAG_FPU_ENABLED;
+        flags |= TB_FLAG_FPU_ENABLED;
     }
 #endif
+    *pflags = flags;
 }
 
 static inline bool tb_fpu_enabled(int tb_flags)
diff --git a/target-sparc/fop_helper.c b/target-sparc/fop_helper.c
index 08306436ac..c7fb176e4c 100644
--- a/target-sparc/fop_helper.c
+++ b/target-sparc/fop_helper.c
@@ -19,48 +19,60 @@
 
 #include "qemu/osdep.h"
 #include "cpu.h"
+#include "exec/exec-all.h"
 #include "exec/helper-proto.h"
 
 #define QT0 (env->qt0)
 #define QT1 (env->qt1)
 
-static void check_ieee_exceptions(CPUSPARCState *env)
+static target_ulong do_check_ieee_exceptions(CPUSPARCState *env, uintptr_t ra)
 {
-    target_ulong status;
+    target_ulong status = get_float_exception_flags(&env->fp_status);
+    target_ulong fsr = env->fsr;
+
+    if (unlikely(status)) {
+        /* Keep exception flags clear for next time.  */
+        set_float_exception_flags(0, &env->fp_status);
 
-    status = get_float_exception_flags(&env->fp_status);
-    if (status) {
         /* Copy IEEE 754 flags into FSR */
         if (status & float_flag_invalid) {
-            env->fsr |= FSR_NVC;
+            fsr |= FSR_NVC;
         }
         if (status & float_flag_overflow) {
-            env->fsr |= FSR_OFC;
+            fsr |= FSR_OFC;
         }
         if (status & float_flag_underflow) {
-            env->fsr |= FSR_UFC;
+            fsr |= FSR_UFC;
         }
         if (status & float_flag_divbyzero) {
-            env->fsr |= FSR_DZC;
+            fsr |= FSR_DZC;
         }
         if (status & float_flag_inexact) {
-            env->fsr |= FSR_NXC;
+            fsr |= FSR_NXC;
         }
 
-        if ((env->fsr & FSR_CEXC_MASK) & ((env->fsr & FSR_TEM_MASK) >> 23)) {
-            /* Unmasked exception, generate a trap */
-            env->fsr |= FSR_FTT_IEEE_EXCP;
-            helper_raise_exception(env, TT_FP_EXCP);
+        if ((fsr & FSR_CEXC_MASK) & ((fsr & FSR_TEM_MASK) >> 23)) {
+            CPUState *cs = CPU(sparc_env_get_cpu(env));
+
+            /* Unmasked exception, generate a trap.  Note that while
+               the helper is marked as NO_WG, we can get away with
+               writing to cpu state along the exception path, since
+               TCG generated code will never see the write.  */
+            env->fsr = fsr | FSR_FTT_IEEE_EXCP;
+            cs->exception_index = TT_FP_EXCP;
+            cpu_loop_exit_restore(cs, ra);
         } else {
             /* Accumulate exceptions */
-            env->fsr |= (env->fsr & FSR_CEXC_MASK) << 5;
+            fsr |= (fsr & FSR_CEXC_MASK) << 5;
         }
     }
+
+    return fsr;
 }
 
-static inline void clear_float_exceptions(CPUSPARCState *env)
+target_ulong helper_check_ieee_exceptions(CPUSPARCState *env)
 {
-    set_float_exception_flags(0, &env->fp_status);
+    return do_check_ieee_exceptions(env, GETPC());
 }
 
 #define F_HELPER(name, p) void helper_f##name##p(CPUSPARCState *env)
@@ -69,26 +81,16 @@ static inline void clear_float_exceptions(CPUSPARCState *env)
     float32 helper_f ## name ## s (CPUSPARCState *env, float32 src1, \
                                    float32 src2)                \
     {                                                           \
-        float32 ret;                                            \
-        clear_float_exceptions(env);                            \
-        ret = float32_ ## name (src1, src2, &env->fp_status);   \
-        check_ieee_exceptions(env);                             \
-        return ret;                                             \
+        return float32_ ## name (src1, src2, &env->fp_status);  \
     }                                                           \
     float64 helper_f ## name ## d (CPUSPARCState * env, float64 src1,\
                                    float64 src2)                \
     {                                                           \
-        float64 ret;                                            \
-        clear_float_exceptions(env);                            \
-        ret = float64_ ## name (src1, src2, &env->fp_status);   \
-        check_ieee_exceptions(env);                             \
-        return ret;                                             \
+        return float64_ ## name (src1, src2, &env->fp_status);  \
     }                                                           \
     F_HELPER(name, q)                                           \
     {                                                           \
-        clear_float_exceptions(env);                            \
         QT0 = float128_ ## name (QT0, QT1, &env->fp_status);    \
-        check_ieee_exceptions(env);                             \
     }
 
 F_BINOP(add);
@@ -99,22 +101,16 @@ F_BINOP(div);
 
 float64 helper_fsmuld(CPUSPARCState *env, float32 src1, float32 src2)
 {
-    float64 ret;
-    clear_float_exceptions(env);
-    ret = float64_mul(float32_to_float64(src1, &env->fp_status),
-                      float32_to_float64(src2, &env->fp_status),
-                      &env->fp_status);
-    check_ieee_exceptions(env);
-    return ret;
+    return float64_mul(float32_to_float64(src1, &env->fp_status),
+                       float32_to_float64(src2, &env->fp_status),
+                       &env->fp_status);
 }
 
 void helper_fdmulq(CPUSPARCState *env, float64 src1, float64 src2)
 {
-    clear_float_exceptions(env);
     QT0 = float128_mul(float64_to_float128(src1, &env->fp_status),
                        float64_to_float128(src2, &env->fp_status),
                        &env->fp_status);
-    check_ieee_exceptions(env);
 }
 
 float32 helper_fnegs(float32 src)
@@ -137,48 +133,32 @@ F_HELPER(neg, q)
 /* Integer to float conversion.  */
 float32 helper_fitos(CPUSPARCState *env, int32_t src)
 {
-    /* Inexact error possible converting int to float.  */
-    float32 ret;
-    clear_float_exceptions(env);
-    ret = int32_to_float32(src, &env->fp_status);
-    check_ieee_exceptions(env);
-    return ret;
+    return int32_to_float32(src, &env->fp_status);
 }
 
 float64 helper_fitod(CPUSPARCState *env, int32_t src)
 {
-    /* No possible exceptions converting int to double.  */
     return int32_to_float64(src, &env->fp_status);
 }
 
 void helper_fitoq(CPUSPARCState *env, int32_t src)
 {
-    /* No possible exceptions converting int to long double.  */
     QT0 = int32_to_float128(src, &env->fp_status);
 }
 
 #ifdef TARGET_SPARC64
 float32 helper_fxtos(CPUSPARCState *env, int64_t src)
 {
-    float32 ret;
-    clear_float_exceptions(env);
-    ret = int64_to_float32(src, &env->fp_status);
-    check_ieee_exceptions(env);
-    return ret;
+    return int64_to_float32(src, &env->fp_status);
 }
 
 float64 helper_fxtod(CPUSPARCState *env, int64_t src)
 {
-    float64 ret;
-    clear_float_exceptions(env);
-    ret = int64_to_float64(src, &env->fp_status);
-    check_ieee_exceptions(env);
-    return ret;
+    return int64_to_float64(src, &env->fp_status);
 }
 
 void helper_fxtoq(CPUSPARCState *env, int64_t src)
 {
-    /* No possible exceptions converting long long to long double.  */
     QT0 = int64_to_float128(src, &env->fp_status);
 }
 #endif
@@ -187,108 +167,64 @@ void helper_fxtoq(CPUSPARCState *env, int64_t src)
 /* floating point conversion */
 float32 helper_fdtos(CPUSPARCState *env, float64 src)
 {
-    float32 ret;
-    clear_float_exceptions(env);
-    ret = float64_to_float32(src, &env->fp_status);
-    check_ieee_exceptions(env);
-    return ret;
+    return float64_to_float32(src, &env->fp_status);
 }
 
 float64 helper_fstod(CPUSPARCState *env, float32 src)
 {
-    float64 ret;
-    clear_float_exceptions(env);
-    ret = float32_to_float64(src, &env->fp_status);
-    check_ieee_exceptions(env);
-    return ret;
+    return float32_to_float64(src, &env->fp_status);
 }
 
 float32 helper_fqtos(CPUSPARCState *env)
 {
-    float32 ret;
-    clear_float_exceptions(env);
-    ret = float128_to_float32(QT1, &env->fp_status);
-    check_ieee_exceptions(env);
-    return ret;
+    return float128_to_float32(QT1, &env->fp_status);
 }
 
 void helper_fstoq(CPUSPARCState *env, float32 src)
 {
-    clear_float_exceptions(env);
     QT0 = float32_to_float128(src, &env->fp_status);
-    check_ieee_exceptions(env);
 }
 
 float64 helper_fqtod(CPUSPARCState *env)
 {
-    float64 ret;
-    clear_float_exceptions(env);
-    ret = float128_to_float64(QT1, &env->fp_status);
-    check_ieee_exceptions(env);
-    return ret;
+    return float128_to_float64(QT1, &env->fp_status);
 }
 
 void helper_fdtoq(CPUSPARCState *env, float64 src)
 {
-    clear_float_exceptions(env);
     QT0 = float64_to_float128(src, &env->fp_status);
-    check_ieee_exceptions(env);
 }
 
 /* Float to integer conversion.  */
 int32_t helper_fstoi(CPUSPARCState *env, float32 src)
 {
-    int32_t ret;
-    clear_float_exceptions(env);
-    ret = float32_to_int32_round_to_zero(src, &env->fp_status);
-    check_ieee_exceptions(env);
-    return ret;
+    return float32_to_int32_round_to_zero(src, &env->fp_status);
 }
 
 int32_t helper_fdtoi(CPUSPARCState *env, float64 src)
 {
-    int32_t ret;
-    clear_float_exceptions(env);
-    ret = float64_to_int32_round_to_zero(src, &env->fp_status);
-    check_ieee_exceptions(env);
-    return ret;
+    return float64_to_int32_round_to_zero(src, &env->fp_status);
 }
 
 int32_t helper_fqtoi(CPUSPARCState *env)
 {
-    int32_t ret;
-    clear_float_exceptions(env);
-    ret = float128_to_int32_round_to_zero(QT1, &env->fp_status);
-    check_ieee_exceptions(env);
-    return ret;
+    return float128_to_int32_round_to_zero(QT1, &env->fp_status);
 }
 
 #ifdef TARGET_SPARC64
 int64_t helper_fstox(CPUSPARCState *env, float32 src)
 {
-    int64_t ret;
-    clear_float_exceptions(env);
-    ret = float32_to_int64_round_to_zero(src, &env->fp_status);
-    check_ieee_exceptions(env);
-    return ret;
+    return float32_to_int64_round_to_zero(src, &env->fp_status);
 }
 
 int64_t helper_fdtox(CPUSPARCState *env, float64 src)
 {
-    int64_t ret;
-    clear_float_exceptions(env);
-    ret = float64_to_int64_round_to_zero(src, &env->fp_status);
-    check_ieee_exceptions(env);
-    return ret;
+    return float64_to_int64_round_to_zero(src, &env->fp_status);
 }
 
 int64_t helper_fqtox(CPUSPARCState *env)
 {
-    int64_t ret;
-    clear_float_exceptions(env);
-    ret = float128_to_int64_round_to_zero(QT1, &env->fp_status);
-    check_ieee_exceptions(env);
-    return ret;
+    return float128_to_int64_round_to_zero(QT1, &env->fp_status);
 }
 #endif
 
@@ -311,87 +247,79 @@ void helper_fabsq(CPUSPARCState *env)
 
 float32 helper_fsqrts(CPUSPARCState *env, float32 src)
 {
-    float32 ret;
-    clear_float_exceptions(env);
-    ret = float32_sqrt(src, &env->fp_status);
-    check_ieee_exceptions(env);
-    return ret;
+    return float32_sqrt(src, &env->fp_status);
 }
 
 float64 helper_fsqrtd(CPUSPARCState *env, float64 src)
 {
-    float64 ret;
-    clear_float_exceptions(env);
-    ret = float64_sqrt(src, &env->fp_status);
-    check_ieee_exceptions(env);
-    return ret;
+    return float64_sqrt(src, &env->fp_status);
 }
 
 void helper_fsqrtq(CPUSPARCState *env)
 {
-    clear_float_exceptions(env);
     QT0 = float128_sqrt(QT1, &env->fp_status);
-    check_ieee_exceptions(env);
 }
 
 #define GEN_FCMP(name, size, reg1, reg2, FS, E)                         \
-    void glue(helper_, name) (CPUSPARCState *env)                       \
+    target_ulong glue(helper_, name) (CPUSPARCState *env)               \
     {                                                                   \
         int ret;                                                        \
-        clear_float_exceptions(env);                                    \
+        target_ulong fsr;                                               \
         if (E) {                                                        \
             ret = glue(size, _compare)(reg1, reg2, &env->fp_status);    \
         } else {                                                        \
             ret = glue(size, _compare_quiet)(reg1, reg2,                \
                                              &env->fp_status);          \
         }                                                               \
-        check_ieee_exceptions(env);                                     \
+        fsr = do_check_ieee_exceptions(env, GETPC());                   \
         switch (ret) {                                                  \
         case float_relation_unordered:                                  \
-            env->fsr |= (FSR_FCC1 | FSR_FCC0) << FS;                    \
-            env->fsr |= FSR_NVA;                                        \
+            fsr |= (FSR_FCC1 | FSR_FCC0) << FS;                         \
+            fsr |= FSR_NVA;                                             \
             break;                                                      \
         case float_relation_less:                                       \
-            env->fsr &= ~(FSR_FCC1) << FS;                              \
-            env->fsr |= FSR_FCC0 << FS;                                 \
+            fsr &= ~(FSR_FCC1) << FS;                                   \
+            fsr |= FSR_FCC0 << FS;                                      \
             break;                                                      \
         case float_relation_greater:                                    \
-            env->fsr &= ~(FSR_FCC0) << FS;                              \
-            env->fsr |= FSR_FCC1 << FS;                                 \
+            fsr &= ~(FSR_FCC0) << FS;                                   \
+            fsr |= FSR_FCC1 << FS;                                      \
             break;                                                      \
         default:                                                        \
-            env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);                 \
+            fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);                      \
             break;                                                      \
         }                                                               \
+        return fsr;                                                     \
     }
 #define GEN_FCMP_T(name, size, FS, E)                                   \
-    void glue(helper_, name)(CPUSPARCState *env, size src1, size src2)  \
+    target_ulong glue(helper_, name)(CPUSPARCState *env, size src1, size src2)\
     {                                                                   \
         int ret;                                                        \
-        clear_float_exceptions(env);                                    \
+        target_ulong fsr;                                               \
         if (E) {                                                        \
             ret = glue(size, _compare)(src1, src2, &env->fp_status);    \
         } else {                                                        \
             ret = glue(size, _compare_quiet)(src1, src2,                \
                                              &env->fp_status);          \
         }                                                               \
-        check_ieee_exceptions(env);                                     \
+        fsr = do_check_ieee_exceptions(env, GETPC());                   \
         switch (ret) {                                                  \
         case float_relation_unordered:                                  \
-            env->fsr |= (FSR_FCC1 | FSR_FCC0) << FS;                    \
+            fsr |= (FSR_FCC1 | FSR_FCC0) << FS;                         \
             break;                                                      \
         case float_relation_less:                                       \
-            env->fsr &= ~(FSR_FCC1 << FS);                              \
-            env->fsr |= FSR_FCC0 << FS;                                 \
+            fsr &= ~(FSR_FCC1 << FS);                                   \
+            fsr |= FSR_FCC0 << FS;                                      \
             break;                                                      \
         case float_relation_greater:                                    \
-            env->fsr &= ~(FSR_FCC0 << FS);                              \
-            env->fsr |= FSR_FCC1 << FS;                                 \
+            fsr &= ~(FSR_FCC0 << FS);                                   \
+            fsr |= FSR_FCC1 << FS;                                      \
             break;                                                      \
         default:                                                        \
-            env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);                 \
+            fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);                      \
             break;                                                      \
         }                                                               \
+        return fsr;                                                     \
     }
 
 GEN_FCMP_T(fcmps, float32, 0, 0);
@@ -431,11 +359,11 @@ GEN_FCMP(fcmpeq_fcc3, float128, QT0, QT1, 26, 1);
 #undef GEN_FCMP_T
 #undef GEN_FCMP
 
-static inline void set_fsr(CPUSPARCState *env)
+static void set_fsr(CPUSPARCState *env, target_ulong fsr)
 {
     int rnd_mode;
 
-    switch (env->fsr & FSR_RD_MASK) {
+    switch (fsr & FSR_RD_MASK) {
     case FSR_RD_NEAREST:
         rnd_mode = float_round_nearest_even;
         break;
@@ -453,16 +381,20 @@ static inline void set_fsr(CPUSPARCState *env)
     set_float_rounding_mode(rnd_mode, &env->fp_status);
 }
 
-void helper_ldfsr(CPUSPARCState *env, uint32_t new_fsr)
+target_ulong helper_ldfsr(CPUSPARCState *env, target_ulong old_fsr,
+                          uint32_t new_fsr)
 {
-    env->fsr = (new_fsr & FSR_LDFSR_MASK) | (env->fsr & FSR_LDFSR_OLDMASK);
-    set_fsr(env);
+    old_fsr = (new_fsr & FSR_LDFSR_MASK) | (old_fsr & FSR_LDFSR_OLDMASK);
+    set_fsr(env, old_fsr);
+    return old_fsr;
 }
 
 #ifdef TARGET_SPARC64
-void helper_ldxfsr(CPUSPARCState *env, uint64_t new_fsr)
+target_ulong helper_ldxfsr(CPUSPARCState *env, target_ulong old_fsr,
+                           uint64_t new_fsr)
 {
-    env->fsr = (new_fsr & FSR_LDXFSR_MASK) | (env->fsr & FSR_LDXFSR_OLDMASK);
-    set_fsr(env);
+    old_fsr = (new_fsr & FSR_LDXFSR_MASK) | (old_fsr & FSR_LDXFSR_OLDMASK);
+    set_fsr(env, old_fsr);
+    return old_fsr;
 }
 #endif
diff --git a/target-sparc/helper.h b/target-sparc/helper.h
index 4374f0dd23..caa2a895d0 100644
--- a/target-sparc/helper.h
+++ b/target-sparc/helper.h
@@ -4,34 +4,32 @@ DEF_HELPER_2(wrpsr, void, env, tl)
 DEF_HELPER_1(rdpsr, tl, env)
 DEF_HELPER_1(power_down, void, env)
 #else
-DEF_HELPER_2(wrpil, void, env, tl)
+DEF_HELPER_FLAGS_2(wrpil, TCG_CALL_NO_RWG, void, env, tl)
 DEF_HELPER_2(wrpstate, void, env, tl)
 DEF_HELPER_1(done, void, env)
 DEF_HELPER_1(retry, void, env)
-DEF_HELPER_1(flushw, void, env)
-DEF_HELPER_1(saved, void, env)
-DEF_HELPER_1(restored, void, env)
+DEF_HELPER_FLAGS_1(flushw, TCG_CALL_NO_WG, void, env)
+DEF_HELPER_FLAGS_1(saved, TCG_CALL_NO_RWG, void, env)
+DEF_HELPER_FLAGS_1(restored, TCG_CALL_NO_RWG, void, env)
 DEF_HELPER_1(rdccr, tl, env)
 DEF_HELPER_2(wrccr, void, env, tl)
 DEF_HELPER_1(rdcwp, tl, env)
 DEF_HELPER_2(wrcwp, void, env, tl)
 DEF_HELPER_FLAGS_2(array8, TCG_CALL_NO_RWG_SE, tl, tl, tl)
-DEF_HELPER_1(popc, tl, tl)
-DEF_HELPER_4(ldda_asi, void, env, tl, int, int)
-DEF_HELPER_5(ldf_asi, void, env, tl, int, int, int)
-DEF_HELPER_5(stf_asi, void, env, tl, int, int, int)
-DEF_HELPER_5(casx_asi, tl, env, tl, tl, tl, i32)
-DEF_HELPER_2(set_softint, void, env, i64)
-DEF_HELPER_2(clear_softint, void, env, i64)
-DEF_HELPER_2(write_softint, void, env, i64)
-DEF_HELPER_2(tick_set_count, void, ptr, i64)
-DEF_HELPER_3(tick_get_count, i64, env, ptr, int)
-DEF_HELPER_2(tick_set_limit, void, ptr, i64)
+DEF_HELPER_FLAGS_1(popc, TCG_CALL_NO_RWG_SE, tl, tl)
+DEF_HELPER_FLAGS_3(ldda_asi, TCG_CALL_NO_WG, void, env, tl, int)
+DEF_HELPER_FLAGS_5(casx_asi, TCG_CALL_NO_WG, tl, env, tl, tl, tl, i32)
+DEF_HELPER_FLAGS_2(set_softint, TCG_CALL_NO_RWG, void, env, i64)
+DEF_HELPER_FLAGS_2(clear_softint, TCG_CALL_NO_RWG, void, env, i64)
+DEF_HELPER_FLAGS_2(write_softint, TCG_CALL_NO_RWG, void, env, i64)
+DEF_HELPER_FLAGS_2(tick_set_count, TCG_CALL_NO_RWG, void, ptr, i64)
+DEF_HELPER_FLAGS_3(tick_get_count, TCG_CALL_NO_WG, i64, env, ptr, int)
+DEF_HELPER_FLAGS_2(tick_set_limit, TCG_CALL_NO_RWG, void, ptr, i64)
 #endif
 #if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64)
-DEF_HELPER_5(cas_asi, tl, env, tl, tl, tl, i32)
+DEF_HELPER_FLAGS_5(cas_asi, TCG_CALL_NO_WG, tl, env, tl, tl, tl, i32)
 #endif
-DEF_HELPER_3(check_align, void, env, tl, i32)
+DEF_HELPER_FLAGS_3(check_align, TCG_CALL_NO_WG, void, env, tl, i32)
 DEF_HELPER_1(debug, void, env)
 DEF_HELPER_1(save, void, env)
 DEF_HELPER_1(restore, void, env)
@@ -42,95 +40,97 @@ DEF_HELPER_3(sdiv_cc, tl, env, tl, tl)
 DEF_HELPER_3(taddcctv, tl, env, tl, tl)
 DEF_HELPER_3(tsubcctv, tl, env, tl, tl)
 #ifdef TARGET_SPARC64
-DEF_HELPER_3(sdivx, s64, env, s64, s64)
-DEF_HELPER_3(udivx, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(sdivx, TCG_CALL_NO_WG, s64, env, s64, s64)
+DEF_HELPER_FLAGS_3(udivx, TCG_CALL_NO_WG, i64, env, i64, i64)
 #endif
-DEF_HELPER_3(ldqf, void, env, tl, int)
-DEF_HELPER_3(stqf, void, env, tl, int)
+DEF_HELPER_FLAGS_3(ldqf, TCG_CALL_NO_WG, void, env, tl, int)
+DEF_HELPER_FLAGS_3(stqf, TCG_CALL_NO_WG, void, env, tl, int)
 #if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64)
-DEF_HELPER_5(ld_asi, i64, env, tl, int, int, int)
-DEF_HELPER_5(st_asi, void, env, tl, i64, int, int)
+DEF_HELPER_FLAGS_4(ld_asi, TCG_CALL_NO_WG, i64, env, tl, int, i32)
+DEF_HELPER_FLAGS_5(st_asi, TCG_CALL_NO_WG, void, env, tl, i64, int, i32)
 #endif
-DEF_HELPER_2(ldfsr, void, env, i32)
+DEF_HELPER_FLAGS_1(check_ieee_exceptions, TCG_CALL_NO_WG, tl, env)
+DEF_HELPER_FLAGS_3(ldfsr, TCG_CALL_NO_RWG, tl, env, tl, i32)
 DEF_HELPER_FLAGS_1(fabss, TCG_CALL_NO_RWG_SE, f32, f32)
-DEF_HELPER_2(fsqrts, f32, env, f32)
-DEF_HELPER_2(fsqrtd, f64, env, f64)
-DEF_HELPER_3(fcmps, void, env, f32, f32)
-DEF_HELPER_3(fcmpd, void, env, f64, f64)
-DEF_HELPER_3(fcmpes, void, env, f32, f32)
-DEF_HELPER_3(fcmped, void, env, f64, f64)
-DEF_HELPER_1(fsqrtq, void, env)
-DEF_HELPER_1(fcmpq, void, env)
-DEF_HELPER_1(fcmpeq, void, env)
+DEF_HELPER_FLAGS_2(fsqrts, TCG_CALL_NO_RWG, f32, env, f32)
+DEF_HELPER_FLAGS_2(fsqrtd, TCG_CALL_NO_RWG, f64, env, f64)
+DEF_HELPER_FLAGS_3(fcmps, TCG_CALL_NO_WG, tl, env, f32, f32)
+DEF_HELPER_FLAGS_3(fcmpd, TCG_CALL_NO_WG, tl, env, f64, f64)
+DEF_HELPER_FLAGS_3(fcmpes, TCG_CALL_NO_WG, tl, env, f32, f32)
+DEF_HELPER_FLAGS_3(fcmped, TCG_CALL_NO_WG, tl, env, f64, f64)
+DEF_HELPER_FLAGS_1(fsqrtq, TCG_CALL_NO_RWG, void, env)
+DEF_HELPER_FLAGS_1(fcmpq, TCG_CALL_NO_WG, tl, env)
+DEF_HELPER_FLAGS_1(fcmpeq, TCG_CALL_NO_WG, tl, env)
 #ifdef TARGET_SPARC64
-DEF_HELPER_2(ldxfsr, void, env, i64)
+DEF_HELPER_FLAGS_3(ldxfsr, TCG_CALL_NO_RWG, tl, env, tl, i64)
 DEF_HELPER_FLAGS_1(fabsd, TCG_CALL_NO_RWG_SE, f64, f64)
-DEF_HELPER_3(fcmps_fcc1, void, env, f32, f32)
-DEF_HELPER_3(fcmps_fcc2, void, env, f32, f32)
-DEF_HELPER_3(fcmps_fcc3, void, env, f32, f32)
-DEF_HELPER_3(fcmpd_fcc1, void, env, f64, f64)
-DEF_HELPER_3(fcmpd_fcc2, void, env, f64, f64)
-DEF_HELPER_3(fcmpd_fcc3, void, env, f64, f64)
-DEF_HELPER_3(fcmpes_fcc1, void, env, f32, f32)
-DEF_HELPER_3(fcmpes_fcc2, void, env, f32, f32)
-DEF_HELPER_3(fcmpes_fcc3, void, env, f32, f32)
-DEF_HELPER_3(fcmped_fcc1, void, env, f64, f64)
-DEF_HELPER_3(fcmped_fcc2, void, env, f64, f64)
-DEF_HELPER_3(fcmped_fcc3, void, env, f64, f64)
-DEF_HELPER_1(fabsq, void, env)
-DEF_HELPER_1(fcmpq_fcc1, void, env)
-DEF_HELPER_1(fcmpq_fcc2, void, env)
-DEF_HELPER_1(fcmpq_fcc3, void, env)
-DEF_HELPER_1(fcmpeq_fcc1, void, env)
-DEF_HELPER_1(fcmpeq_fcc2, void, env)
-DEF_HELPER_1(fcmpeq_fcc3, void, env)
+DEF_HELPER_FLAGS_3(fcmps_fcc1, TCG_CALL_NO_WG, tl, env, f32, f32)
+DEF_HELPER_FLAGS_3(fcmps_fcc2, TCG_CALL_NO_WG, tl, env, f32, f32)
+DEF_HELPER_FLAGS_3(fcmps_fcc3, TCG_CALL_NO_WG, tl, env, f32, f32)
+DEF_HELPER_FLAGS_3(fcmpd_fcc1, TCG_CALL_NO_WG, tl, env, f64, f64)
+DEF_HELPER_FLAGS_3(fcmpd_fcc2, TCG_CALL_NO_WG, tl, env, f64, f64)
+DEF_HELPER_FLAGS_3(fcmpd_fcc3, TCG_CALL_NO_WG, tl, env, f64, f64)
+DEF_HELPER_FLAGS_3(fcmpes_fcc1, TCG_CALL_NO_WG, tl, env, f32, f32)
+DEF_HELPER_FLAGS_3(fcmpes_fcc2, TCG_CALL_NO_WG, tl, env, f32, f32)
+DEF_HELPER_FLAGS_3(fcmpes_fcc3, TCG_CALL_NO_WG, tl, env, f32, f32)
+DEF_HELPER_FLAGS_3(fcmped_fcc1, TCG_CALL_NO_WG, tl, env, f64, f64)
+DEF_HELPER_FLAGS_3(fcmped_fcc2, TCG_CALL_NO_WG, tl, env, f64, f64)
+DEF_HELPER_FLAGS_3(fcmped_fcc3, TCG_CALL_NO_WG, tl, env, f64, f64)
+DEF_HELPER_FLAGS_1(fabsq, TCG_CALL_NO_RWG, void, env)
+DEF_HELPER_FLAGS_1(fcmpq_fcc1, TCG_CALL_NO_WG, tl, env)
+DEF_HELPER_FLAGS_1(fcmpq_fcc2, TCG_CALL_NO_WG, tl, env)
+DEF_HELPER_FLAGS_1(fcmpq_fcc3, TCG_CALL_NO_WG, tl, env)
+DEF_HELPER_FLAGS_1(fcmpeq_fcc1, TCG_CALL_NO_WG, tl, env)
+DEF_HELPER_FLAGS_1(fcmpeq_fcc2, TCG_CALL_NO_WG, tl, env)
+DEF_HELPER_FLAGS_1(fcmpeq_fcc3, TCG_CALL_NO_WG, tl, env)
 #endif
 DEF_HELPER_2(raise_exception, noreturn, env, int)
-#define F_HELPER_0_1(name) DEF_HELPER_1(f ## name, void, env)
+#define F_HELPER_0_1(name) \
+  DEF_HELPER_FLAGS_1(f ## name, TCG_CALL_NO_RWG, void, env)
 
-DEF_HELPER_3(faddd, f64, env, f64, f64)
-DEF_HELPER_3(fsubd, f64, env, f64, f64)
-DEF_HELPER_3(fmuld, f64, env, f64, f64)
-DEF_HELPER_3(fdivd, f64, env, f64, f64)
+DEF_HELPER_FLAGS_3(faddd, TCG_CALL_NO_RWG, f64, env, f64, f64)
+DEF_HELPER_FLAGS_3(fsubd, TCG_CALL_NO_RWG, f64, env, f64, f64)
+DEF_HELPER_FLAGS_3(fmuld, TCG_CALL_NO_RWG, f64, env, f64, f64)
+DEF_HELPER_FLAGS_3(fdivd, TCG_CALL_NO_RWG, f64, env, f64, f64)
 F_HELPER_0_1(addq)
 F_HELPER_0_1(subq)
 F_HELPER_0_1(mulq)
 F_HELPER_0_1(divq)
 
-DEF_HELPER_3(fadds, f32, env, f32, f32)
-DEF_HELPER_3(fsubs, f32, env, f32, f32)
-DEF_HELPER_3(fmuls, f32, env, f32, f32)
-DEF_HELPER_3(fdivs, f32, env, f32, f32)
+DEF_HELPER_FLAGS_3(fadds, TCG_CALL_NO_RWG, f32, env, f32, f32)
+DEF_HELPER_FLAGS_3(fsubs, TCG_CALL_NO_RWG, f32, env, f32, f32)
+DEF_HELPER_FLAGS_3(fmuls, TCG_CALL_NO_RWG, f32, env, f32, f32)
+DEF_HELPER_FLAGS_3(fdivs, TCG_CALL_NO_RWG, f32, env, f32, f32)
 
-DEF_HELPER_3(fsmuld, f64, env, f32, f32)
-DEF_HELPER_3(fdmulq, void, env, f64, f64)
+DEF_HELPER_FLAGS_3(fsmuld, TCG_CALL_NO_RWG, f64, env, f32, f32)
+DEF_HELPER_FLAGS_3(fdmulq, TCG_CALL_NO_RWG, void, env, f64, f64)
 
 DEF_HELPER_FLAGS_1(fnegs, TCG_CALL_NO_RWG_SE, f32, f32)
-DEF_HELPER_2(fitod, f64, env, s32)
-DEF_HELPER_2(fitoq, void, env, s32)
+DEF_HELPER_FLAGS_2(fitod, TCG_CALL_NO_RWG_SE, f64, env, s32)
+DEF_HELPER_FLAGS_2(fitoq, TCG_CALL_NO_RWG, void, env, s32)
 
-DEF_HELPER_2(fitos, f32, env, s32)
+DEF_HELPER_FLAGS_2(fitos, TCG_CALL_NO_RWG, f32, env, s32)
 
 #ifdef TARGET_SPARC64
 DEF_HELPER_FLAGS_1(fnegd, TCG_CALL_NO_RWG_SE, f64, f64)
-DEF_HELPER_1(fnegq, void, env)
-DEF_HELPER_2(fxtos, f32, env, s64)
-DEF_HELPER_2(fxtod, f64, env, s64)
-DEF_HELPER_2(fxtoq, void, env, s64)
+DEF_HELPER_FLAGS_1(fnegq, TCG_CALL_NO_RWG, void, env)
+DEF_HELPER_FLAGS_2(fxtos, TCG_CALL_NO_RWG, f32, env, s64)
+DEF_HELPER_FLAGS_2(fxtod, TCG_CALL_NO_RWG, f64, env, s64)
+DEF_HELPER_FLAGS_2(fxtoq, TCG_CALL_NO_RWG, void, env, s64)
 #endif
-DEF_HELPER_2(fdtos, f32, env, f64)
-DEF_HELPER_2(fstod, f64, env, f32)
-DEF_HELPER_1(fqtos, f32, env)
-DEF_HELPER_2(fstoq, void, env, f32)
-DEF_HELPER_1(fqtod, f64, env)
-DEF_HELPER_2(fdtoq, void, env, f64)
-DEF_HELPER_2(fstoi, s32, env, f32)
-DEF_HELPER_2(fdtoi, s32, env, f64)
-DEF_HELPER_1(fqtoi, s32, env)
+DEF_HELPER_FLAGS_2(fdtos, TCG_CALL_NO_RWG, f32, env, f64)
+DEF_HELPER_FLAGS_2(fstod, TCG_CALL_NO_RWG, f64, env, f32)
+DEF_HELPER_FLAGS_1(fqtos, TCG_CALL_NO_RWG, f32, env)
+DEF_HELPER_FLAGS_2(fstoq, TCG_CALL_NO_RWG, void, env, f32)
+DEF_HELPER_FLAGS_1(fqtod, TCG_CALL_NO_RWG, f64, env)
+DEF_HELPER_FLAGS_2(fdtoq, TCG_CALL_NO_RWG, void, env, f64)
+DEF_HELPER_FLAGS_2(fstoi, TCG_CALL_NO_RWG, s32, env, f32)
+DEF_HELPER_FLAGS_2(fdtoi, TCG_CALL_NO_RWG, s32, env, f64)
+DEF_HELPER_FLAGS_1(fqtoi, TCG_CALL_NO_RWG, s32, env)
 #ifdef TARGET_SPARC64
-DEF_HELPER_2(fstox, s64, env, f32)
-DEF_HELPER_2(fdtox, s64, env, f64)
-DEF_HELPER_1(fqtox, s64, env)
+DEF_HELPER_FLAGS_2(fstox, TCG_CALL_NO_RWG, s64, env, f32)
+DEF_HELPER_FLAGS_2(fdtox, TCG_CALL_NO_RWG, s64, env, f64)
+DEF_HELPER_FLAGS_1(fqtox, TCG_CALL_NO_RWG, s64, env)
 
 DEF_HELPER_FLAGS_2(fpmerge, TCG_CALL_NO_RWG_SE, i64, i64, i64)
 DEF_HELPER_FLAGS_2(fmul8x16, TCG_CALL_NO_RWG_SE, i64, i64, i64)
@@ -172,4 +172,4 @@ VIS_CMPHELPER(cmpne)
 #undef VIS_HELPER
 #undef VIS_CMPHELPER
 DEF_HELPER_1(compute_psr, void, env)
-DEF_HELPER_1(compute_C_icc, i32, env)
+DEF_HELPER_FLAGS_1(compute_C_icc, TCG_CALL_NO_WG_SE, i32, env)
diff --git a/target-sparc/ldst_helper.c b/target-sparc/ldst_helper.c
index e941cacc9e..6ce5ccc37f 100644
--- a/target-sparc/ldst_helper.c
+++ b/target-sparc/ldst_helper.c
@@ -19,9 +19,11 @@
 
 #include "qemu/osdep.h"
 #include "cpu.h"
+#include "tcg.h"
 #include "exec/helper-proto.h"
 #include "exec/exec-all.h"
 #include "exec/cpu_ldst.h"
+#include "asi.h"
 
 //#define DEBUG_MMU
 //#define DEBUG_MXCC
@@ -427,9 +429,11 @@ static uint64_t leon3_cache_control_ld(CPUSPARCState *env, target_ulong addr,
     return ret;
 }
 
-uint64_t helper_ld_asi(CPUSPARCState *env, target_ulong addr, int asi, int size,
-                       int sign)
+uint64_t helper_ld_asi(CPUSPARCState *env, target_ulong addr,
+                       int asi, uint32_t memop)
 {
+    int size = 1 << (memop & MO_SIZE);
+    int sign = memop & MO_SIGN;
     CPUState *cs = CPU(sparc_env_get_cpu(env));
     uint64_t ret = 0;
 #if defined(DEBUG_MXCC) || defined(DEBUG_ASI)
@@ -438,7 +442,8 @@ uint64_t helper_ld_asi(CPUSPARCState *env, target_ulong addr, int asi, int size,
 
     helper_check_align(env, addr, size - 1);
     switch (asi) {
-    case 2: /* SuperSparc MXCC registers and Leon3 cache control */
+    case ASI_M_MXCC: /* SuperSparc MXCC registers, or... */
+    /* case ASI_LEON_CACHEREGS:  Leon3 cache control */
         switch (addr) {
         case 0x00:          /* Leon3 Cache Control */
         case 0x08:          /* Leon3 Instruction Cache config */
@@ -497,8 +502,8 @@ uint64_t helper_ld_asi(CPUSPARCState *env, target_ulong addr, int asi, int size,
         dump_mxcc(env);
 #endif
         break;
-    case 3: /* MMU probe */
-    case 0x18: /* LEON3 MMU probe */
+    case ASI_M_FLUSH_PROBE: /* SuperSparc MMU probe */
+    case ASI_LEON_MMUFLUSH: /* LEON3 MMU probe */
         {
             int mmulev;
 
@@ -512,8 +517,8 @@ uint64_t helper_ld_asi(CPUSPARCState *env, target_ulong addr, int asi, int size,
                         addr, mmulev, ret);
         }
         break;
-    case 4: /* read MMU regs */
-    case 0x19: /* LEON3 read MMU regs */
+    case ASI_M_MMUREGS: /* SuperSparc MMU regs */
+    case ASI_LEON_MMUREGS: /* LEON3 MMU regs */
         {
             int reg = (addr >> 8) & 0x1f;
 
@@ -528,11 +533,11 @@ uint64_t helper_ld_asi(CPUSPARCState *env, target_ulong addr, int asi, int size,
             DPRINTF_MMU("mmu_read: reg[%d] = 0x%08" PRIx64 "\n", reg, ret);
         }
         break;
-    case 5: /* Turbosparc ITLB Diagnostic */
-    case 6: /* Turbosparc DTLB Diagnostic */
-    case 7: /* Turbosparc IOTLB Diagnostic */
+    case ASI_M_TLBDIAG: /* Turbosparc ITLB Diagnostic */
+    case ASI_M_DIAGS:   /* Turbosparc DTLB Diagnostic */
+    case ASI_M_IODIAG:  /* Turbosparc IOTLB Diagnostic */
         break;
-    case 9: /* Supervisor code access */
+    case ASI_KERNELTXT: /* Supervisor code access */
         switch (size) {
         case 1:
             ret = cpu_ldub_code(env, addr);
@@ -549,7 +554,7 @@ uint64_t helper_ld_asi(CPUSPARCState *env, target_ulong addr, int asi, int size,
             break;
         }
         break;
-    case 0xa: /* User data access */
+    case ASI_USERDATA: /* User data access */
         switch (size) {
         case 1:
             ret = cpu_ldub_user(env, addr);
@@ -566,8 +571,8 @@ uint64_t helper_ld_asi(CPUSPARCState *env, target_ulong addr, int asi, int size,
             break;
         }
         break;
-    case 0xb: /* Supervisor data access */
-    case 0x80:
+    case ASI_KERNELDATA: /* Supervisor data access */
+    case ASI_P: /* Implicit primary context data access (v9 only?) */
         switch (size) {
         case 1:
             ret = cpu_ldub_kernel(env, addr);
@@ -584,13 +589,13 @@ uint64_t helper_ld_asi(CPUSPARCState *env, target_ulong addr, int asi, int size,
             break;
         }
         break;
-    case 0xc: /* I-cache tag */
-    case 0xd: /* I-cache data */
-    case 0xe: /* D-cache tag */
-    case 0xf: /* D-cache data */
+    case ASI_M_TXTC_TAG:   /* SparcStation 5 I-cache tag */
+    case ASI_M_TXTC_DATA:  /* SparcStation 5 I-cache data */
+    case ASI_M_DATAC_TAG:  /* SparcStation 5 D-cache tag */
+    case ASI_M_DATAC_DATA: /* SparcStation 5 D-cache data */
         break;
-    case 0x20: /* MMU passthrough */
-    case 0x1c: /* LEON MMU passthrough */
+    case ASI_M_BYPASS:    /* MMU passthrough */
+    case ASI_LEON_BYPASS: /* LEON MMU passthrough */
         switch (size) {
         case 1:
             ret = ldub_phys(cs->as, addr);
@@ -669,7 +674,7 @@ uint64_t helper_ld_asi(CPUSPARCState *env, target_ulong addr, int asi, int size,
     case 0x4c: /* SuperSPARC MMU Breakpoint Action */
         ret = env->mmubpaction;
         break;
-    case 8: /* User code access, XXX */
+    case ASI_USERTXT: /* User code access, XXX */
     default:
         cpu_unassigned_access(cs, addr, false, false, asi, size);
         ret = 0;
@@ -696,15 +701,17 @@ uint64_t helper_ld_asi(CPUSPARCState *env, target_ulong addr, int asi, int size,
     return ret;
 }
 
-void helper_st_asi(CPUSPARCState *env, target_ulong addr, uint64_t val, int asi,
-                   int size)
+void helper_st_asi(CPUSPARCState *env, target_ulong addr, uint64_t val,
+                   int asi, uint32_t memop)
 {
+    int size = 1 << (memop & MO_SIZE);
     SPARCCPU *cpu = sparc_env_get_cpu(env);
     CPUState *cs = CPU(cpu);
 
     helper_check_align(env, addr, size - 1);
     switch (asi) {
-    case 2: /* SuperSparc MXCC registers and Leon3 cache control */
+    case ASI_M_MXCC: /* SuperSparc MXCC registers, or... */
+    /* case ASI_LEON_CACHEREGS:  Leon3 cache control */
         switch (addr) {
         case 0x00:          /* Leon3 Cache Control */
         case 0x08:          /* Leon3 Instruction Cache config */
@@ -838,8 +845,8 @@ void helper_st_asi(CPUSPARCState *env, target_ulong addr, uint64_t val, int asi,
         dump_mxcc(env);
 #endif
         break;
-    case 3: /* MMU flush */
-    case 0x18: /* LEON3 MMU flush */
+    case ASI_M_FLUSH_PROBE: /* SuperSparc MMU flush */
+    case ASI_LEON_MMUFLUSH: /* LEON3 MMU flush */
         {
             int mmulev;
 
@@ -863,8 +870,8 @@ void helper_st_asi(CPUSPARCState *env, target_ulong addr, uint64_t val, int asi,
 #endif
         }
         break;
-    case 4: /* write MMU regs */
-    case 0x19: /* LEON3 write MMU regs */
+    case ASI_M_MMUREGS: /* write MMU regs */
+    case ASI_LEON_MMUREGS: /* LEON3 write MMU regs */
         {
             int reg = (addr >> 8) & 0x1f;
             uint32_t oldreg;
@@ -918,11 +925,11 @@ void helper_st_asi(CPUSPARCState *env, target_ulong addr, uint64_t val, int asi,
 #endif
         }
         break;
-    case 5: /* Turbosparc ITLB Diagnostic */
-    case 6: /* Turbosparc DTLB Diagnostic */
-    case 7: /* Turbosparc IOTLB Diagnostic */
+    case ASI_M_TLBDIAG: /* Turbosparc ITLB Diagnostic */
+    case ASI_M_DIAGS:   /* Turbosparc DTLB Diagnostic */
+    case ASI_M_IODIAG:  /* Turbosparc IOTLB Diagnostic */
         break;
-    case 0xa: /* User data access */
+    case ASI_USERDATA: /* User data access */
         switch (size) {
         case 1:
             cpu_stb_user(env, addr, val);
@@ -939,8 +946,8 @@ void helper_st_asi(CPUSPARCState *env, target_ulong addr, uint64_t val, int asi,
             break;
         }
         break;
-    case 0xb: /* Supervisor data access */
-    case 0x80:
+    case ASI_KERNELDATA: /* Supervisor data access */
+    case ASI_P:
         switch (size) {
         case 1:
             cpu_stb_kernel(env, addr, val);
@@ -957,17 +964,17 @@ void helper_st_asi(CPUSPARCState *env, target_ulong addr, uint64_t val, int asi,
             break;
         }
         break;
-    case 0xc: /* I-cache tag */
-    case 0xd: /* I-cache data */
-    case 0xe: /* D-cache tag */
-    case 0xf: /* D-cache data */
-    case 0x10: /* I/D-cache flush page */
-    case 0x11: /* I/D-cache flush segment */
-    case 0x12: /* I/D-cache flush region */
-    case 0x13: /* I/D-cache flush context */
-    case 0x14: /* I/D-cache flush user */
+    case ASI_M_TXTC_TAG:   /* I-cache tag */
+    case ASI_M_TXTC_DATA:  /* I-cache data */
+    case ASI_M_DATAC_TAG:  /* D-cache tag */
+    case ASI_M_DATAC_DATA: /* D-cache data */
+    case ASI_M_FLUSH_PAGE:   /* I/D-cache flush page */
+    case ASI_M_FLUSH_SEG:    /* I/D-cache flush segment */
+    case ASI_M_FLUSH_REGION: /* I/D-cache flush region */
+    case ASI_M_FLUSH_CTX:    /* I/D-cache flush context */
+    case ASI_M_FLUSH_USER:   /* I/D-cache flush user */
         break;
-    case 0x17: /* Block copy, sta access */
+    case ASI_M_BCOPY: /* Block copy, sta access */
         {
             /* val = src
                addr = dst
@@ -981,20 +988,20 @@ void helper_st_asi(CPUSPARCState *env, target_ulong addr, uint64_t val, int asi,
             }
         }
         break;
-    case 0x1f: /* Block fill, stda access */
+    case ASI_M_BFILL: /* Block fill, stda access */
         {
             /* addr = dst
                fill 32 bytes with val */
             unsigned int i;
-            uint32_t dst = addr & 7;
+            uint32_t dst = addr & ~7;
 
             for (i = 0; i < 32; i += 8, dst += 8) {
                 cpu_stq_kernel(env, dst, val);
             }
         }
         break;
-    case 0x20: /* MMU passthrough */
-    case 0x1c: /* LEON MMU passthrough */
+    case ASI_M_BYPASS:    /* MMU passthrough */
+    case ASI_LEON_BYPASS: /* LEON MMU passthrough */
         {
             switch (size) {
             case 1:
@@ -1078,8 +1085,8 @@ void helper_st_asi(CPUSPARCState *env, target_ulong addr, uint64_t val, int asi,
     case 0x4c: /* SuperSPARC MMU Breakpoint Action */
         env->mmubpaction = val & 0x1fff;
         break;
-    case 8: /* User code access, XXX */
-    case 9: /* Supervisor code access, XXX */
+    case ASI_USERTXT: /* User code access, XXX */
+    case ASI_KERNELTXT: /* Supervisor code access, XXX */
     default:
         cpu_unassigned_access(CPU(sparc_env_get_cpu(env)),
                               addr, true, false, asi, size);
@@ -1094,9 +1101,11 @@ void helper_st_asi(CPUSPARCState *env, target_ulong addr, uint64_t val, int asi,
 #else /* TARGET_SPARC64 */
 
 #ifdef CONFIG_USER_ONLY
-uint64_t helper_ld_asi(CPUSPARCState *env, target_ulong addr, int asi, int size,
-                       int sign)
+uint64_t helper_ld_asi(CPUSPARCState *env, target_ulong addr,
+                       int asi, uint32_t memop)
 {
+    int size = 1 << (memop & MO_SIZE);
+    int sign = memop & MO_SIGN;
     uint64_t ret = 0;
 #if defined(DEBUG_ASI)
     target_ulong last_addr = addr;
@@ -1110,8 +1119,8 @@ uint64_t helper_ld_asi(CPUSPARCState *env, target_ulong addr, int asi, int size,
     addr = asi_address_mask(env, asi, addr);
 
     switch (asi) {
-    case 0x82: /* Primary no-fault */
-    case 0x8a: /* Primary no-fault LE */
+    case ASI_PNF:  /* Primary no-fault */
+    case ASI_PNFL: /* Primary no-fault LE */
         if (page_check_range(addr, size, PAGE_READ) == -1) {
 #ifdef DEBUG_ASI
             dump_asi("read ", last_addr, asi, size, ret);
@@ -1119,8 +1128,8 @@ uint64_t helper_ld_asi(CPUSPARCState *env, target_ulong addr, int asi, int size,
             return 0;
         }
         /* Fall through */
-    case 0x80: /* Primary */
-    case 0x88: /* Primary LE */
+    case ASI_P: /* Primary */
+    case ASI_PL: /* Primary LE */
         {
             switch (size) {
             case 1:
@@ -1139,8 +1148,8 @@ uint64_t helper_ld_asi(CPUSPARCState *env, target_ulong addr, int asi, int size,
             }
         }
         break;
-    case 0x83: /* Secondary no-fault */
-    case 0x8b: /* Secondary no-fault LE */
+    case ASI_SNF:  /* Secondary no-fault */
+    case ASI_SNFL: /* Secondary no-fault LE */
         if (page_check_range(addr, size, PAGE_READ) == -1) {
 #ifdef DEBUG_ASI
             dump_asi("read ", last_addr, asi, size, ret);
@@ -1148,8 +1157,8 @@ uint64_t helper_ld_asi(CPUSPARCState *env, target_ulong addr, int asi, int size,
             return 0;
         }
         /* Fall through */
-    case 0x81: /* Secondary */
-    case 0x89: /* Secondary LE */
+    case ASI_S:  /* Secondary */
+    case ASI_SL: /* Secondary LE */
         /* XXX */
         break;
     default:
@@ -1158,10 +1167,10 @@ uint64_t helper_ld_asi(CPUSPARCState *env, target_ulong addr, int asi, int size,
 
     /* Convert from little endian */
     switch (asi) {
-    case 0x88: /* Primary LE */
-    case 0x89: /* Secondary LE */
-    case 0x8a: /* Primary no-fault LE */
-    case 0x8b: /* Secondary no-fault LE */
+    case ASI_PL:   /* Primary LE */
+    case ASI_SL:   /* Secondary LE */
+    case ASI_PNFL: /* Primary no-fault LE */
+    case ASI_SNFL: /* Secondary no-fault LE */
         switch (size) {
         case 2:
             ret = bswap16(ret);
@@ -1202,8 +1211,9 @@ uint64_t helper_ld_asi(CPUSPARCState *env, target_ulong addr, int asi, int size,
 }
 
 void helper_st_asi(CPUSPARCState *env, target_ulong addr, target_ulong val,
-                   int asi, int size)
+                   int asi, uint32_t memop)
 {
+    int size = 1 << (memop & MO_SIZE);
 #ifdef DEBUG_ASI
     dump_asi("write", addr, asi, size, val);
 #endif
@@ -1216,8 +1226,8 @@ void helper_st_asi(CPUSPARCState *env, target_ulong addr, target_ulong val,
 
     /* Convert to little endian */
     switch (asi) {
-    case 0x88: /* Primary LE */
-    case 0x89: /* Secondary LE */
+    case ASI_PL: /* Primary LE */
+    case ASI_SL: /* Secondary LE */
         switch (size) {
         case 2:
             val = bswap16(val);
@@ -1236,8 +1246,8 @@ void helper_st_asi(CPUSPARCState *env, target_ulong addr, target_ulong val,
     }
 
     switch (asi) {
-    case 0x80: /* Primary */
-    case 0x88: /* Primary LE */
+    case ASI_P:  /* Primary */
+    case ASI_PL: /* Primary LE */
         {
             switch (size) {
             case 1:
@@ -1256,15 +1266,15 @@ void helper_st_asi(CPUSPARCState *env, target_ulong addr, target_ulong val,
             }
         }
         break;
-    case 0x81: /* Secondary */
-    case 0x89: /* Secondary LE */
+    case ASI_S:  /* Secondary */
+    case ASI_SL: /* Secondary LE */
         /* XXX */
         return;
 
-    case 0x82: /* Primary no-fault, RO */
-    case 0x83: /* Secondary no-fault, RO */
-    case 0x8a: /* Primary no-fault LE, RO */
-    case 0x8b: /* Secondary no-fault LE, RO */
+    case ASI_PNF:  /* Primary no-fault, RO */
+    case ASI_SNF:  /* Secondary no-fault, RO */
+    case ASI_PNFL: /* Primary no-fault LE, RO */
+    case ASI_SNFL: /* Secondary no-fault LE, RO */
     default:
         helper_raise_exception(env, TT_DATA_ACCESS);
         return;
@@ -1273,9 +1283,11 @@ void helper_st_asi(CPUSPARCState *env, target_ulong addr, target_ulong val,
 
 #else /* CONFIG_USER_ONLY */
 
-uint64_t helper_ld_asi(CPUSPARCState *env, target_ulong addr, int asi, int size,
-                       int sign)
+uint64_t helper_ld_asi(CPUSPARCState *env, target_ulong addr,
+                       int asi, uint32_t memop)
 {
+    int size = 1 << (memop & MO_SIZE);
+    int sign = memop & MO_SIGN;
     CPUState *cs = CPU(sparc_env_get_cpu(env));
     uint64_t ret = 0;
 #if defined(DEBUG_ASI)
@@ -1318,16 +1330,14 @@ uint64_t helper_ld_asi(CPUSPARCState *env, target_ulong addr, int asi, int size,
     }
 
     switch (asi) {
-    case 0x10: /* As if user primary */
-    case 0x11: /* As if user secondary */
-    case 0x18: /* As if user primary LE */
-    case 0x19: /* As if user secondary LE */
-    case 0x80: /* Primary */
-    case 0x81: /* Secondary */
-    case 0x88: /* Primary LE */
-    case 0x89: /* Secondary LE */
-    case 0xe2: /* UA2007 Primary block init */
-    case 0xe3: /* UA2007 Secondary block init */
+    case ASI_AIUP:  /* As if user primary */
+    case ASI_AIUS:  /* As if user secondary */
+    case ASI_AIUPL: /* As if user primary LE */
+    case ASI_AIUSL: /* As if user secondary LE */
+    case ASI_P:  /* Primary */
+    case ASI_S:  /* Secondary */
+    case ASI_PL: /* Primary LE */
+    case ASI_SL: /* Secondary LE */
         if ((asi & 0x80) && (env->pstate & PS_PRIV)) {
             if (cpu_hypervisor_mode(env)) {
                 switch (size) {
@@ -1418,10 +1428,10 @@ uint64_t helper_ld_asi(CPUSPARCState *env, target_ulong addr, int asi, int size,
             }
         }
         break;
-    case 0x14: /* Bypass */
-    case 0x15: /* Bypass, non-cacheable */
-    case 0x1c: /* Bypass LE */
-    case 0x1d: /* Bypass, non-cacheable LE */
+    case ASI_REAL:        /* Bypass */
+    case ASI_REAL_IO:   /* Bypass, non-cacheable */
+    case ASI_REAL_L:      /* Bypass LE */
+    case ASI_REAL_IO_L: /* Bypass, non-cacheable LE */
         {
             switch (size) {
             case 1:
@@ -1440,13 +1450,8 @@ uint64_t helper_ld_asi(CPUSPARCState *env, target_ulong addr, int asi, int size,
             }
             break;
         }
-    case 0x24: /* Nucleus quad LDD 128 bit atomic */
-    case 0x2c: /* Nucleus quad LDD 128 bit atomic LE
-                  Only ldda allowed */
-        helper_raise_exception(env, TT_ILL_INSN);
-        return 0;
-    case 0x04: /* Nucleus */
-    case 0x0c: /* Nucleus Little Endian (LE) */
+    case ASI_N:  /* Nucleus */
+    case ASI_NL: /* Nucleus Little Endian (LE) */
         {
             switch (size) {
             case 1:
@@ -1465,13 +1470,13 @@ uint64_t helper_ld_asi(CPUSPARCState *env, target_ulong addr, int asi, int size,
             }
             break;
         }
-    case 0x4a: /* UPA config */
+    case ASI_UPA_CONFIG: /* UPA config */
         /* XXX */
         break;
-    case 0x45: /* LSU */
+    case ASI_LSU_CONTROL: /* LSU */
         ret = env->lsu;
         break;
-    case 0x50: /* I-MMU regs */
+    case ASI_IMMU: /* I-MMU regs */
         {
             int reg = (addr >> 3) & 0xf;
 
@@ -1484,7 +1489,7 @@ uint64_t helper_ld_asi(CPUSPARCState *env, target_ulong addr, int asi, int size,
 
             break;
         }
-    case 0x51: /* I-MMU 8k TSB pointer */
+    case ASI_IMMU_TSB_8KB_PTR: /* I-MMU 8k TSB pointer */
         {
             /* env->immuregs[5] holds I-MMU TSB register value
                env->immuregs[6] holds I-MMU Tag Access register value */
@@ -1492,7 +1497,7 @@ uint64_t helper_ld_asi(CPUSPARCState *env, target_ulong addr, int asi, int size,
                                          8*1024);
             break;
         }
-    case 0x52: /* I-MMU 64k TSB pointer */
+    case ASI_IMMU_TSB_64KB_PTR: /* I-MMU 64k TSB pointer */
         {
             /* env->immuregs[5] holds I-MMU TSB register value
                env->immuregs[6] holds I-MMU Tag Access register value */
@@ -1500,21 +1505,21 @@ uint64_t helper_ld_asi(CPUSPARCState *env, target_ulong addr, int asi, int size,
                                          64*1024);
             break;
         }
-    case 0x55: /* I-MMU data access */
+    case ASI_ITLB_DATA_ACCESS: /* I-MMU data access */
         {
             int reg = (addr >> 3) & 0x3f;
 
             ret = env->itlb[reg].tte;
             break;
         }
-    case 0x56: /* I-MMU tag read */
+    case ASI_ITLB_TAG_READ: /* I-MMU tag read */
         {
             int reg = (addr >> 3) & 0x3f;
 
             ret = env->itlb[reg].tag;
             break;
         }
-    case 0x58: /* D-MMU regs */
+    case ASI_DMMU: /* D-MMU regs */
         {
             int reg = (addr >> 3) & 0xf;
 
@@ -1526,7 +1531,7 @@ uint64_t helper_ld_asi(CPUSPARCState *env, target_ulong addr, int asi, int size,
             }
             break;
         }
-    case 0x59: /* D-MMU 8k TSB pointer */
+    case ASI_DMMU_TSB_8KB_PTR: /* D-MMU 8k TSB pointer */
         {
             /* env->dmmuregs[5] holds D-MMU TSB register value
                env->dmmuregs[6] holds D-MMU Tag Access register value */
@@ -1534,7 +1539,7 @@ uint64_t helper_ld_asi(CPUSPARCState *env, target_ulong addr, int asi, int size,
                                          8*1024);
             break;
         }
-    case 0x5a: /* D-MMU 64k TSB pointer */
+    case ASI_DMMU_TSB_64KB_PTR: /* D-MMU 64k TSB pointer */
         {
             /* env->dmmuregs[5] holds D-MMU TSB register value
                env->dmmuregs[6] holds D-MMU Tag Access register value */
@@ -1542,26 +1547,26 @@ uint64_t helper_ld_asi(CPUSPARCState *env, target_ulong addr, int asi, int size,
                                          64*1024);
             break;
         }
-    case 0x5d: /* D-MMU data access */
+    case ASI_DTLB_DATA_ACCESS: /* D-MMU data access */
         {
             int reg = (addr >> 3) & 0x3f;
 
             ret = env->dtlb[reg].tte;
             break;
         }
-    case 0x5e: /* D-MMU tag read */
+    case ASI_DTLB_TAG_READ: /* D-MMU tag read */
         {
             int reg = (addr >> 3) & 0x3f;
 
             ret = env->dtlb[reg].tag;
             break;
         }
-    case 0x48: /* Interrupt dispatch, RO */
+    case ASI_INTR_DISPATCH_STAT: /* Interrupt dispatch, RO */
         break;
-    case 0x49: /* Interrupt data receive */
+    case ASI_INTR_RECEIVE: /* Interrupt data receive */
         ret = env->ivec_status;
         break;
-    case 0x7f: /* Incoming interrupt vector, RO */
+    case ASI_INTR_R: /* Incoming interrupt vector, RO */
         {
             int reg = (addr >> 4) & 0x3;
             if (reg < 3) {
@@ -1569,40 +1574,59 @@ uint64_t helper_ld_asi(CPUSPARCState *env, target_ulong addr, int asi, int size,
             }
             break;
         }
-    case 0x46: /* D-cache data */
-    case 0x47: /* D-cache tag access */
-    case 0x4b: /* E-cache error enable */
-    case 0x4c: /* E-cache asynchronous fault status */
-    case 0x4d: /* E-cache asynchronous fault address */
-    case 0x4e: /* E-cache tag data */
-    case 0x66: /* I-cache instruction access */
-    case 0x67: /* I-cache tag access */
-    case 0x6e: /* I-cache predecode */
-    case 0x6f: /* I-cache LRU etc. */
-    case 0x76: /* E-cache tag */
-    case 0x7e: /* E-cache tag */
-        break;
-    case 0x5b: /* D-MMU data pointer */
-    case 0x54: /* I-MMU data in, WO */
-    case 0x57: /* I-MMU demap, WO */
-    case 0x5c: /* D-MMU data in, WO */
-    case 0x5f: /* D-MMU demap, WO */
-    case 0x77: /* Interrupt vector, WO */
+    case ASI_DCACHE_DATA:     /* D-cache data */
+    case ASI_DCACHE_TAG:      /* D-cache tag access */
+    case ASI_ESTATE_ERROR_EN: /* E-cache error enable */
+    case ASI_AFSR:            /* E-cache asynchronous fault status */
+    case ASI_AFAR:            /* E-cache asynchronous fault address */
+    case ASI_EC_TAG_DATA:     /* E-cache tag data */
+    case ASI_IC_INSTR:        /* I-cache instruction access */
+    case ASI_IC_TAG:          /* I-cache tag access */
+    case ASI_IC_PRE_DECODE:   /* I-cache predecode */
+    case ASI_IC_NEXT_FIELD:   /* I-cache LRU etc. */
+    case ASI_EC_W:            /* E-cache tag */
+    case ASI_EC_R:            /* E-cache tag */
+        break;
+    case ASI_DMMU_TSB_DIRECT_PTR: /* D-MMU data pointer */
+    case ASI_ITLB_DATA_IN:        /* I-MMU data in, WO */
+    case ASI_IMMU_DEMAP:          /* I-MMU demap, WO */
+    case ASI_DTLB_DATA_IN:        /* D-MMU data in, WO */
+    case ASI_DMMU_DEMAP:          /* D-MMU demap, WO */
+    case ASI_INTR_W:              /* Interrupt vector, WO */
     default:
         cpu_unassigned_access(cs, addr, false, false, 1, size);
         ret = 0;
         break;
+
+    case ASI_NUCLEUS_QUAD_LDD:   /* Nucleus quad LDD 128 bit atomic */
+    case ASI_NUCLEUS_QUAD_LDD_L: /* Nucleus quad LDD 128 bit atomic LE */
+    case ASI_TWINX_AIUP:   /* As if user primary, twinx */
+    case ASI_TWINX_AIUS:   /* As if user secondary, twinx */
+    case ASI_TWINX_REAL:   /* Real address, twinx */
+    case ASI_TWINX_AIUP_L: /* As if user primary, twinx, LE */
+    case ASI_TWINX_AIUS_L: /* As if user secondary, twinx, LE */
+    case ASI_TWINX_REAL_L: /* Real address, twinx, LE */
+    case ASI_TWINX_N:  /* Nucleus, twinx */
+    case ASI_TWINX_NL: /* Nucleus, twinx, LE */
+    /* ??? From the UA2011 document; overlaps BLK_INIT_QUAD_LDD_* */
+    case ASI_TWINX_P:  /* Primary, twinx */
+    case ASI_TWINX_PL: /* Primary, twinx, LE */
+    case ASI_TWINX_S:  /* Secondary, twinx */
+    case ASI_TWINX_SL: /* Secondary, twinx, LE */
+        /* These are all 128-bit atomic; only ldda (now ldtxa) allowed */
+        helper_raise_exception(env, TT_ILL_INSN);
+        return 0;
     }
 
     /* Convert from little endian */
     switch (asi) {
-    case 0x0c: /* Nucleus Little Endian (LE) */
-    case 0x18: /* As if user primary LE */
-    case 0x19: /* As if user secondary LE */
-    case 0x1c: /* Bypass LE */
-    case 0x1d: /* Bypass, non-cacheable LE */
-    case 0x88: /* Primary LE */
-    case 0x89: /* Secondary LE */
+    case ASI_NL: /* Nucleus Little Endian (LE) */
+    case ASI_AIUPL: /* As if user primary LE */
+    case ASI_AIUSL: /* As if user secondary LE */
+    case ASI_REAL_L:      /* Bypass LE */
+    case ASI_REAL_IO_L: /* Bypass, non-cacheable LE */
+    case ASI_PL: /* Primary LE */
+    case ASI_SL: /* Secondary LE */
         switch(size) {
         case 2:
             ret = bswap16(ret);
@@ -1643,8 +1667,9 @@ uint64_t helper_ld_asi(CPUSPARCState *env, target_ulong addr, int asi, int size,
 }
 
 void helper_st_asi(CPUSPARCState *env, target_ulong addr, target_ulong val,
-                   int asi, int size)
+                   int asi, uint32_t memop)
 {
+    int size = 1 << (memop & MO_SIZE);
     SPARCCPU *cpu = sparc_env_get_cpu(env);
     CPUState *cs = CPU(cpu);
 
@@ -1666,13 +1691,13 @@ void helper_st_asi(CPUSPARCState *env, target_ulong addr, target_ulong val,
 
     /* Convert to little endian */
     switch (asi) {
-    case 0x0c: /* Nucleus Little Endian (LE) */
-    case 0x18: /* As if user primary LE */
-    case 0x19: /* As if user secondary LE */
-    case 0x1c: /* Bypass LE */
-    case 0x1d: /* Bypass, non-cacheable LE */
-    case 0x88: /* Primary LE */
-    case 0x89: /* Secondary LE */
+    case ASI_NL: /* Nucleus Little Endian (LE) */
+    case ASI_AIUPL: /* As if user primary LE */
+    case ASI_AIUSL: /* As if user secondary LE */
+    case ASI_REAL_L: /* Bypass LE */
+    case ASI_REAL_IO_L: /* Bypass, non-cacheable LE */
+    case ASI_PL: /* Primary LE */
+    case ASI_SL: /* Secondary LE */
         switch (size) {
         case 2:
             val = bswap16(val);
@@ -1691,16 +1716,14 @@ void helper_st_asi(CPUSPARCState *env, target_ulong addr, target_ulong val,
     }
 
     switch (asi) {
-    case 0x10: /* As if user primary */
-    case 0x11: /* As if user secondary */
-    case 0x18: /* As if user primary LE */
-    case 0x19: /* As if user secondary LE */
-    case 0x80: /* Primary */
-    case 0x81: /* Secondary */
-    case 0x88: /* Primary LE */
-    case 0x89: /* Secondary LE */
-    case 0xe2: /* UA2007 Primary block init */
-    case 0xe3: /* UA2007 Secondary block init */
+    case ASI_AIUP:  /* As if user primary */
+    case ASI_AIUS:  /* As if user secondary */
+    case ASI_AIUPL: /* As if user primary LE */
+    case ASI_AIUSL: /* As if user secondary LE */
+    case ASI_P:  /* Primary */
+    case ASI_S:  /* Secondary */
+    case ASI_PL: /* Primary LE */
+    case ASI_SL: /* Secondary LE */
         if ((asi & 0x80) && (env->pstate & PS_PRIV)) {
             if (cpu_hypervisor_mode(env)) {
                 switch (size) {
@@ -1791,10 +1814,10 @@ void helper_st_asi(CPUSPARCState *env, target_ulong addr, target_ulong val,
             }
         }
         break;
-    case 0x14: /* Bypass */
-    case 0x15: /* Bypass, non-cacheable */
-    case 0x1c: /* Bypass LE */
-    case 0x1d: /* Bypass, non-cacheable LE */
+    case ASI_REAL:      /* Bypass */
+    case ASI_REAL_IO:   /* Bypass, non-cacheable */
+    case ASI_REAL_L:    /* Bypass LE */
+    case ASI_REAL_IO_L: /* Bypass, non-cacheable LE */
         {
             switch (size) {
             case 1:
@@ -1813,13 +1836,8 @@ void helper_st_asi(CPUSPARCState *env, target_ulong addr, target_ulong val,
             }
         }
         return;
-    case 0x24: /* Nucleus quad LDD 128 bit atomic */
-    case 0x2c: /* Nucleus quad LDD 128 bit atomic LE
-                  Only ldda allowed */
-        helper_raise_exception(env, TT_ILL_INSN);
-        return;
-    case 0x04: /* Nucleus */
-    case 0x0c: /* Nucleus Little Endian (LE) */
+    case ASI_N:  /* Nucleus */
+    case ASI_NL: /* Nucleus Little Endian (LE) */
         {
             switch (size) {
             case 1:
@@ -1839,10 +1857,10 @@ void helper_st_asi(CPUSPARCState *env, target_ulong addr, target_ulong val,
             break;
         }
 
-    case 0x4a: /* UPA config */
+    case ASI_UPA_CONFIG: /* UPA config */
         /* XXX */
         return;
-    case 0x45: /* LSU */
+    case ASI_LSU_CONTROL: /* LSU */
         {
             uint64_t oldreg;
 
@@ -1860,7 +1878,7 @@ void helper_st_asi(CPUSPARCState *env, target_ulong addr, target_ulong val,
             }
             return;
         }
-    case 0x50: /* I-MMU regs */
+    case ASI_IMMU: /* I-MMU regs */
         {
             int reg = (addr >> 3) & 0xf;
             uint64_t oldreg;
@@ -1904,10 +1922,10 @@ void helper_st_asi(CPUSPARCState *env, target_ulong addr, target_ulong val,
 #endif
             return;
         }
-    case 0x54: /* I-MMU data in */
+    case ASI_ITLB_DATA_IN: /* I-MMU data in */
         replace_tlb_1bit_lru(env->itlb, env->immu.tag_access, val, "immu", env);
         return;
-    case 0x55: /* I-MMU data access */
+    case ASI_ITLB_DATA_ACCESS: /* I-MMU data access */
         {
             /* TODO: auto demap */
 
@@ -1921,10 +1939,10 @@ void helper_st_asi(CPUSPARCState *env, target_ulong addr, target_ulong val,
 #endif
             return;
         }
-    case 0x57: /* I-MMU demap */
+    case ASI_IMMU_DEMAP: /* I-MMU demap */
         demap_tlb(env->itlb, addr, "immu", env);
         return;
-    case 0x58: /* D-MMU regs */
+    case ASI_DMMU: /* D-MMU regs */
         {
             int reg = (addr >> 3) & 0xf;
             uint64_t oldreg;
@@ -1977,10 +1995,10 @@ void helper_st_asi(CPUSPARCState *env, target_ulong addr, target_ulong val,
 #endif
             return;
         }
-    case 0x5c: /* D-MMU data in */
+    case ASI_DTLB_DATA_IN: /* D-MMU data in */
         replace_tlb_1bit_lru(env->dtlb, env->dmmu.tag_access, val, "dmmu", env);
         return;
-    case 0x5d: /* D-MMU data access */
+    case ASI_DTLB_DATA_ACCESS: /* D-MMU data access */
         {
             unsigned int i = (addr >> 3) & 0x3f;
 
@@ -1992,38 +2010,56 @@ void helper_st_asi(CPUSPARCState *env, target_ulong addr, target_ulong val,
 #endif
             return;
         }
-    case 0x5f: /* D-MMU demap */
+    case ASI_DMMU_DEMAP: /* D-MMU demap */
         demap_tlb(env->dtlb, addr, "dmmu", env);
         return;
-    case 0x49: /* Interrupt data receive */
+    case ASI_INTR_RECEIVE: /* Interrupt data receive */
         env->ivec_status = val & 0x20;
         return;
-    case 0x46: /* D-cache data */
-    case 0x47: /* D-cache tag access */
-    case 0x4b: /* E-cache error enable */
-    case 0x4c: /* E-cache asynchronous fault status */
-    case 0x4d: /* E-cache asynchronous fault address */
-    case 0x4e: /* E-cache tag data */
-    case 0x66: /* I-cache instruction access */
-    case 0x67: /* I-cache tag access */
-    case 0x6e: /* I-cache predecode */
-    case 0x6f: /* I-cache LRU etc. */
-    case 0x76: /* E-cache tag */
-    case 0x7e: /* E-cache tag */
+    case ASI_NUCLEUS_QUAD_LDD:   /* Nucleus quad LDD 128 bit atomic */
+    case ASI_NUCLEUS_QUAD_LDD_L: /* Nucleus quad LDD 128 bit atomic LE */
+    case ASI_TWINX_AIUP:   /* As if user primary, twinx */
+    case ASI_TWINX_AIUS:   /* As if user secondary, twinx */
+    case ASI_TWINX_REAL:   /* Real address, twinx */
+    case ASI_TWINX_AIUP_L: /* As if user primary, twinx, LE */
+    case ASI_TWINX_AIUS_L: /* As if user secondary, twinx, LE */
+    case ASI_TWINX_REAL_L: /* Real address, twinx, LE */
+    case ASI_TWINX_N:  /* Nucleus, twinx */
+    case ASI_TWINX_NL: /* Nucleus, twinx, LE */
+    /* ??? From the UA2011 document; overlaps BLK_INIT_QUAD_LDD_* */
+    case ASI_TWINX_P:  /* Primary, twinx */
+    case ASI_TWINX_PL: /* Primary, twinx, LE */
+    case ASI_TWINX_S:  /* Secondary, twinx */
+    case ASI_TWINX_SL: /* Secondary, twinx, LE */
+        /* Only stda allowed */
+        helper_raise_exception(env, TT_ILL_INSN);
+        return;
+    case ASI_DCACHE_DATA: /* D-cache data */
+    case ASI_DCACHE_TAG: /* D-cache tag access */
+    case ASI_ESTATE_ERROR_EN: /* E-cache error enable */
+    case ASI_AFSR: /* E-cache asynchronous fault status */
+    case ASI_AFAR: /* E-cache asynchronous fault address */
+    case ASI_EC_TAG_DATA: /* E-cache tag data */
+    case ASI_IC_INSTR: /* I-cache instruction access */
+    case ASI_IC_TAG: /* I-cache tag access */
+    case ASI_IC_PRE_DECODE: /* I-cache predecode */
+    case ASI_IC_NEXT_FIELD: /* I-cache LRU etc. */
+    case ASI_EC_W: /* E-cache tag */
+    case ASI_EC_R: /* E-cache tag */
         return;
-    case 0x51: /* I-MMU 8k TSB pointer, RO */
-    case 0x52: /* I-MMU 64k TSB pointer, RO */
-    case 0x56: /* I-MMU tag read, RO */
-    case 0x59: /* D-MMU 8k TSB pointer, RO */
-    case 0x5a: /* D-MMU 64k TSB pointer, RO */
-    case 0x5b: /* D-MMU data pointer, RO */
-    case 0x5e: /* D-MMU tag read, RO */
-    case 0x48: /* Interrupt dispatch, RO */
-    case 0x7f: /* Incoming interrupt vector, RO */
-    case 0x82: /* Primary no-fault, RO */
-    case 0x83: /* Secondary no-fault, RO */
-    case 0x8a: /* Primary no-fault LE, RO */
-    case 0x8b: /* Secondary no-fault LE, RO */
+    case ASI_IMMU_TSB_8KB_PTR: /* I-MMU 8k TSB pointer, RO */
+    case ASI_IMMU_TSB_64KB_PTR: /* I-MMU 64k TSB pointer, RO */
+    case ASI_ITLB_TAG_READ: /* I-MMU tag read, RO */
+    case ASI_DMMU_TSB_8KB_PTR: /* D-MMU 8k TSB pointer, RO */
+    case ASI_DMMU_TSB_64KB_PTR: /* D-MMU 64k TSB pointer, RO */
+    case ASI_DMMU_TSB_DIRECT_PTR: /* D-MMU data pointer, RO */
+    case ASI_DTLB_TAG_READ: /* D-MMU tag read, RO */
+    case ASI_INTR_DISPATCH_STAT: /* Interrupt dispatch, RO */
+    case ASI_INTR_R: /* Incoming interrupt vector, RO */
+    case ASI_PNF: /* Primary no-fault, RO */
+    case ASI_SNF: /* Secondary no-fault, RO */
+    case ASI_PNFL: /* Primary no-fault LE, RO */
+    case ASI_SNFL: /* Secondary no-fault LE, RO */
     default:
         cpu_unassigned_access(cs, addr, true, false, 1, size);
         return;
@@ -2031,8 +2067,11 @@ void helper_st_asi(CPUSPARCState *env, target_ulong addr, target_ulong val,
 }
 #endif /* CONFIG_USER_ONLY */
 
-void helper_ldda_asi(CPUSPARCState *env, target_ulong addr, int asi, int rd)
+/* 128-bit LDDA; result returned in QT0.  */
+void helper_ldda_asi(CPUSPARCState *env, target_ulong addr, int asi)
 {
+    uint64_t h, l;
+
     if ((asi < 0x80 && (env->pstate & PS_PRIV) == 0)
         || (cpu_has_hypervisor(env)
             && asi >= 0x30 && asi < 0x80
@@ -2044,191 +2083,82 @@ void helper_ldda_asi(CPUSPARCState *env, target_ulong addr, int asi, int rd)
 
     switch (asi) {
 #if !defined(CONFIG_USER_ONLY)
-    case 0x24: /* Nucleus quad LDD 128 bit atomic */
-    case 0x2c: /* Nucleus quad LDD 128 bit atomic LE */
+    case ASI_TWINX_AIUP:   /* As if user primary, twinx */
+    case ASI_TWINX_AIUP_L: /* As if user primary, twinx, LE */
         helper_check_align(env, addr, 0xf);
-        if (rd == 0) {
-            env->gregs[1] = cpu_ldq_nucleus(env, addr + 8);
-            if (asi == 0x2c) {
-                bswap64s(&env->gregs[1]);
-            }
-        } else if (rd < 8) {
-            env->gregs[rd] = cpu_ldq_nucleus(env, addr);
-            env->gregs[rd + 1] = cpu_ldq_nucleus(env, addr + 8);
-            if (asi == 0x2c) {
-                bswap64s(&env->gregs[rd]);
-                bswap64s(&env->gregs[rd + 1]);
-            }
-        } else {
-            env->regwptr[rd - 8] = cpu_ldq_nucleus(env, addr);
-            env->regwptr[rd + 1 - 8] = cpu_ldq_nucleus(env, addr + 8);
-            if (asi == 0x2c) {
-                bswap64s(&env->regwptr[rd - 8]);
-                bswap64s(&env->regwptr[rd + 1 - 8]);
-            }
-        }
+        h = cpu_ldq_user(env, addr);
+        l = cpu_ldq_user(env, addr + 8);
         break;
-#endif
-    default:
-        helper_check_align(env, addr, 0x3);
-        if (rd == 0) {
-            env->gregs[1] = helper_ld_asi(env, addr + 4, asi, 4, 0);
-        } else if (rd < 8) {
-            env->gregs[rd] = helper_ld_asi(env, addr, asi, 4, 0);
-            env->gregs[rd + 1] = helper_ld_asi(env, addr + 4, asi, 4, 0);
-        } else {
-            env->regwptr[rd - 8] = helper_ld_asi(env, addr, asi, 4, 0);
-            env->regwptr[rd + 1 - 8] = helper_ld_asi(env, addr + 4, asi, 4, 0);
-        }
+    case ASI_TWINX_AIUS:   /* As if user secondary, twinx */
+    case ASI_TWINX_AIUS_L: /* As if user secondary, twinx, LE */
+        helper_check_align(env, addr, 0xf);
+        h = cpu_ldq_user_secondary(env, addr);
+        l = cpu_ldq_user_secondary(env, addr + 8);
         break;
-    }
-}
-
-void helper_ldf_asi(CPUSPARCState *env, target_ulong addr, int asi, int size,
-                    int rd)
-{
-    unsigned int i;
-    target_ulong val;
-
-    helper_check_align(env, addr, 3);
-    addr = asi_address_mask(env, asi, addr);
-
-    switch (asi) {
-    case 0xf0: /* UA2007/JPS1 Block load primary */
-    case 0xf1: /* UA2007/JPS1 Block load secondary */
-    case 0xf8: /* UA2007/JPS1 Block load primary LE */
-    case 0xf9: /* UA2007/JPS1 Block load secondary LE */
-        if (rd & 7) {
-            helper_raise_exception(env, TT_ILL_INSN);
-            return;
-        }
-        helper_check_align(env, addr, 0x3f);
-        for (i = 0; i < 8; i++, rd += 2, addr += 8) {
-            env->fpr[rd / 2].ll = helper_ld_asi(env, addr, asi & 0x8f, 8, 0);
-        }
-        return;
-
-    case 0x16: /* UA2007 Block load primary, user privilege */
-    case 0x17: /* UA2007 Block load secondary, user privilege */
-    case 0x1e: /* UA2007 Block load primary LE, user privilege */
-    case 0x1f: /* UA2007 Block load secondary LE, user privilege */
-    case 0x70: /* JPS1 Block load primary, user privilege */
-    case 0x71: /* JPS1 Block load secondary, user privilege */
-    case 0x78: /* JPS1 Block load primary LE, user privilege */
-    case 0x79: /* JPS1 Block load secondary LE, user privilege */
-        if (rd & 7) {
-            helper_raise_exception(env, TT_ILL_INSN);
-            return;
-        }
-        helper_check_align(env, addr, 0x3f);
-        for (i = 0; i < 8; i++, rd += 2, addr += 8) {
-            env->fpr[rd / 2].ll = helper_ld_asi(env, addr, asi & 0x19, 8, 0);
+    case ASI_TWINX_REAL:   /* Real address, twinx */
+    case ASI_TWINX_REAL_L: /* Real address, twinx, LE */
+        helper_check_align(env, addr, 0xf);
+        {
+            CPUState *cs = CPU(sparc_env_get_cpu(env));
+            h = ldq_phys(cs->as, addr);
+            l = ldq_phys(cs->as, addr + 8);
         }
-        return;
-
-    default:
         break;
-    }
-
-    switch (size) {
-    default:
-    case 4:
-        val = helper_ld_asi(env, addr, asi, size, 0);
-        if (rd & 1) {
-            env->fpr[rd / 2].l.lower = val;
-        } else {
-            env->fpr[rd / 2].l.upper = val;
+    case ASI_NUCLEUS_QUAD_LDD:
+    case ASI_NUCLEUS_QUAD_LDD_L:
+    case ASI_TWINX_N:  /* Nucleus, twinx */
+    case ASI_TWINX_NL: /* Nucleus, twinx, LE */
+        helper_check_align(env, addr, 0xf);
+        h = cpu_ldq_nucleus(env, addr);
+        l = cpu_ldq_nucleus(env, addr + 8);
+        break;
+    case ASI_TWINX_S: /* Secondary, twinx */
+    case ASI_TWINX_SL: /* Secondary, twinx, LE */
+        if (!cpu_hypervisor_mode(env)) {
+            helper_check_align(env, addr, 0xf);
+            if (env->pstate & PS_PRIV) {
+                h = cpu_ldq_kernel_secondary(env, addr);
+                l = cpu_ldq_kernel_secondary(env, addr + 8);
+            } else {
+                h = cpu_ldq_user_secondary(env, addr);
+                l = cpu_ldq_user_secondary(env, addr + 8);
+            }
+            break;
         }
+        /* fallthru */
+    case ASI_TWINX_P:  /* Primary, twinx */
+    case ASI_TWINX_PL: /* Primary, twinx, LE */
+        helper_check_align(env, addr, 0xf);
+        h = cpu_ldq_data(env, addr);
+        l = cpu_ldq_data(env, addr + 8);
         break;
-    case 8:
-        env->fpr[rd / 2].ll = helper_ld_asi(env, addr, asi, size, 0);
-        break;
-    case 16:
-        env->fpr[rd / 2].ll = helper_ld_asi(env, addr, asi, 8, 0);
-        env->fpr[rd / 2 + 1].ll = helper_ld_asi(env, addr + 8, asi, 8, 0);
-        break;
-    }
-}
-
-void helper_stf_asi(CPUSPARCState *env, target_ulong addr, int asi, int size,
-                    int rd)
-{
-    unsigned int i;
-    target_ulong val;
-
-    addr = asi_address_mask(env, asi, addr);
-
-    switch (asi) {
-    case 0xe0: /* UA2007/JPS1 Block commit store primary (cache flush) */
-    case 0xe1: /* UA2007/JPS1 Block commit store secondary (cache flush) */
-    case 0xf0: /* UA2007/JPS1 Block store primary */
-    case 0xf1: /* UA2007/JPS1 Block store secondary */
-    case 0xf8: /* UA2007/JPS1 Block store primary LE */
-    case 0xf9: /* UA2007/JPS1 Block store secondary LE */
-        if (rd & 7) {
-            helper_raise_exception(env, TT_ILL_INSN);
-            return;
-        }
-        helper_check_align(env, addr, 0x3f);
-        for (i = 0; i < 8; i++, rd += 2, addr += 8) {
-            helper_st_asi(env, addr, env->fpr[rd / 2].ll, asi & 0x8f, 8);
-        }
-
-        return;
-    case 0x16: /* UA2007 Block load primary, user privilege */
-    case 0x17: /* UA2007 Block load secondary, user privilege */
-    case 0x1e: /* UA2007 Block load primary LE, user privilege */
-    case 0x1f: /* UA2007 Block load secondary LE, user privilege */
-    case 0x70: /* JPS1 Block store primary, user privilege */
-    case 0x71: /* JPS1 Block store secondary, user privilege */
-    case 0x78: /* JPS1 Block load primary LE, user privilege */
-    case 0x79: /* JPS1 Block load secondary LE, user privilege */
-        if (rd & 7) {
-            helper_raise_exception(env, TT_ILL_INSN);
-            return;
-        }
-        helper_check_align(env, addr, 0x3f);
-        for (i = 0; i < 8; i++, rd += 2, addr += 8) {
-            helper_st_asi(env, addr, env->fpr[rd / 2].ll, asi & 0x19, 8);
-        }
-
-        return;
-    case 0xd2: /* 16-bit floating point load primary */
-    case 0xd3: /* 16-bit floating point load secondary */
-    case 0xda: /* 16-bit floating point load primary, LE */
-    case 0xdb: /* 16-bit floating point load secondary, LE */
-        helper_check_align(env, addr, 1);
-        /* Fall through */
-    case 0xd0: /* 8-bit floating point load primary */
-    case 0xd1: /* 8-bit floating point load secondary */
-    case 0xd8: /* 8-bit floating point load primary, LE */
-    case 0xd9: /* 8-bit floating point load secondary, LE */
-        val = env->fpr[rd / 2].l.lower;
-        helper_st_asi(env, addr, val, asi & 0x8d, ((asi & 2) >> 1) + 1);
-        return;
+#else
+    case ASI_TWINX_P:  /* Primary, twinx */
+    case ASI_TWINX_PL: /* Primary, twinx, LE */
+    case ASI_TWINX_S:  /* Primary, twinx */
+    case ASI_TWINX_SL: /* Primary, twinx, LE */
+        /* ??? Should be available, but we need to implement
+           an atomic 128-bit load.  */
+        helper_raise_exception(env, TT_PRIV_ACT);
+#endif
     default:
-        helper_check_align(env, addr, 3);
-        break;
+        /* Non-twinx asi, so this is the legacy ldda insn, which
+           performs two word sized operations.  */
+        /* ??? The UA2011 manual recommends emulating this with
+           a single 64-bit load.  However, LE asis *are* treated
+           as two 32-bit loads individually byte swapped.  */
+        helper_check_align(env, addr, 0x7);
+        QT0.high = (uint32_t)helper_ld_asi(env, addr, asi, MO_UL);
+        QT0.low = (uint32_t)helper_ld_asi(env, addr + 4, asi, MO_UL);
+        return;
     }
 
-    switch (size) {
-    default:
-    case 4:
-        if (rd & 1) {
-            val = env->fpr[rd / 2].l.lower;
-        } else {
-            val = env->fpr[rd / 2].l.upper;
-        }
-        helper_st_asi(env, addr, val, asi, size);
-        break;
-    case 8:
-        helper_st_asi(env, addr, env->fpr[rd / 2].ll, asi, size);
-        break;
-    case 16:
-        helper_st_asi(env, addr, env->fpr[rd / 2].ll, asi, 8);
-        helper_st_asi(env, addr + 8, env->fpr[rd / 2 + 1].ll, asi, 8);
-        break;
+    if (asi & 8) {
+        h = bswap64(h);
+        l = bswap64(l);
     }
+    QT0.high = h;
+    QT0.low = l;
 }
 
 target_ulong helper_casx_asi(CPUSPARCState *env, target_ulong addr,
@@ -2237,9 +2167,9 @@ target_ulong helper_casx_asi(CPUSPARCState *env, target_ulong addr,
 {
     target_ulong ret;
 
-    ret = helper_ld_asi(env, addr, asi, 8, 0);
+    ret = helper_ld_asi(env, addr, asi, MO_Q);
     if (val2 == ret) {
-        helper_st_asi(env, addr, val1, asi, 8);
+        helper_st_asi(env, addr, val1, asi, MO_Q);
     }
     return ret;
 }
@@ -2252,10 +2182,10 @@ target_ulong helper_cas_asi(CPUSPARCState *env, target_ulong addr,
     target_ulong ret;
 
     val2 &= 0xffffffffUL;
-    ret = helper_ld_asi(env, addr, asi, 4, 0);
+    ret = helper_ld_asi(env, addr, asi, MO_UL);
     ret &= 0xffffffffUL;
     if (val2 == ret) {
-        helper_st_asi(env, addr, val1 & 0xffffffffUL, asi, 4);
+        helper_st_asi(env, addr, val1 & 0xffffffffUL, asi, MO_UL);
     }
     return ret;
 }
diff --git a/target-sparc/translate.c b/target-sparc/translate.c
index 0f4faf7062..e7691e4458 100644
--- a/target-sparc/translate.c
+++ b/target-sparc/translate.c
@@ -31,6 +31,7 @@
 
 #include "trace-tcg.h"
 #include "exec/log.h"
+#include "asi.h"
 
 
 #define DEBUG_DISAS
@@ -53,11 +54,10 @@ static TCGv cpu_tbr;
 #endif
 static TCGv cpu_cond;
 #ifdef TARGET_SPARC64
-static TCGv_i32 cpu_xcc, cpu_asi, cpu_fprs;
+static TCGv_i32 cpu_xcc, cpu_fprs;
 static TCGv cpu_gsr;
 static TCGv cpu_tick_cmpr, cpu_stick_cmpr, cpu_hstick_cmpr;
 static TCGv cpu_hintp, cpu_htba, cpu_hver, cpu_ssr, cpu_ver;
-static TCGv_i32 cpu_softint;
 #else
 static TCGv cpu_wim;
 #endif
@@ -82,6 +82,10 @@ typedef struct DisasContext {
     TCGv ttl[5];
     int n_t32;
     int n_ttl;
+#ifdef TARGET_SPARC64
+    int fprs_dirty;
+    int asi;
+#endif
 } DisasContext;
 
 typedef struct {
@@ -137,10 +141,16 @@ static inline TCGv get_temp_tl(DisasContext *dc)
     return t;
 }
 
-static inline void gen_update_fprs_dirty(int rd)
+static inline void gen_update_fprs_dirty(DisasContext *dc, int rd)
 {
 #if defined(TARGET_SPARC64)
-    tcg_gen_ori_i32(cpu_fprs, cpu_fprs, (rd < 32) ? 1 : 2);
+    int bit = (rd < 32) ? 1 : 2;
+    /* If we know we've already set this bit within the TB,
+       we can avoid setting it again.  */
+    if (!(dc->fprs_dirty & bit)) {
+        dc->fprs_dirty |= bit;
+        tcg_gen_ori_i32(cpu_fprs, cpu_fprs, bit);
+    }
 #endif
 }
 
@@ -182,7 +192,7 @@ static void gen_store_fpr_F(DisasContext *dc, unsigned int dst, TCGv_i32 v)
     tcg_gen_deposit_i64(cpu_fpr[dst / 2], cpu_fpr[dst / 2], t,
                         (dst & 1 ? 0 : 32), 32);
 #endif
-    gen_update_fprs_dirty(dst);
+    gen_update_fprs_dirty(dc, dst);
 }
 
 static TCGv_i32 gen_dest_fpr_F(DisasContext *dc)
@@ -200,7 +210,7 @@ static void gen_store_fpr_D(DisasContext *dc, unsigned int dst, TCGv_i64 v)
 {
     dst = DFPREG(dst);
     tcg_gen_mov_i64(cpu_fpr[dst / 2], v);
-    gen_update_fprs_dirty(dst);
+    gen_update_fprs_dirty(dc, dst);
 }
 
 static TCGv_i64 gen_dest_fpr_D(DisasContext *dc, unsigned int dst)
@@ -233,14 +243,14 @@ static void gen_op_store_QT0_fpr(unsigned int dst)
 }
 
 #ifdef TARGET_SPARC64
-static void gen_move_Q(unsigned int rd, unsigned int rs)
+static void gen_move_Q(DisasContext *dc, unsigned int rd, unsigned int rs)
 {
     rd = QFPREG(rd);
     rs = QFPREG(rs);
 
     tcg_gen_mov_i64(cpu_fpr[rd / 2], cpu_fpr[rs / 2]);
     tcg_gen_mov_i64(cpu_fpr[rd / 2 + 1], cpu_fpr[rs / 2 + 1]);
-    gen_update_fprs_dirty(rd);
+    gen_update_fprs_dirty(dc, rd);
 }
 #endif
 
@@ -1044,6 +1054,24 @@ static inline void save_state(DisasContext *dc)
     save_npc(dc);
 }
 
+static void gen_exception(DisasContext *dc, int which)
+{
+    TCGv_i32 t;
+
+    save_state(dc);
+    t = tcg_const_i32(which);
+    gen_helper_raise_exception(cpu_env, t);
+    tcg_temp_free_i32(t);
+    dc->is_br = 1;
+}
+
+static void gen_check_align(TCGv addr, int mask)
+{
+    TCGv_i32 r_mask = tcg_const_i32(mask);
+    gen_helper_check_align(cpu_env, addr, r_mask);
+    tcg_temp_free_i32(r_mask);
+}
+
 static inline void gen_mov_pc_npc(DisasContext *dc)
 {
     if (dc->npc == JUMP_PC) {
@@ -1497,16 +1525,16 @@ static inline void gen_op_fcmps(int fccno, TCGv_i32 r_rs1, TCGv_i32 r_rs2)
 {
     switch (fccno) {
     case 0:
-        gen_helper_fcmps(cpu_env, r_rs1, r_rs2);
+        gen_helper_fcmps(cpu_fsr, cpu_env, r_rs1, r_rs2);
         break;
     case 1:
-        gen_helper_fcmps_fcc1(cpu_env, r_rs1, r_rs2);
+        gen_helper_fcmps_fcc1(cpu_fsr, cpu_env, r_rs1, r_rs2);
         break;
     case 2:
-        gen_helper_fcmps_fcc2(cpu_env, r_rs1, r_rs2);
+        gen_helper_fcmps_fcc2(cpu_fsr, cpu_env, r_rs1, r_rs2);
         break;
     case 3:
-        gen_helper_fcmps_fcc3(cpu_env, r_rs1, r_rs2);
+        gen_helper_fcmps_fcc3(cpu_fsr, cpu_env, r_rs1, r_rs2);
         break;
     }
 }
@@ -1515,16 +1543,16 @@ static inline void gen_op_fcmpd(int fccno, TCGv_i64 r_rs1, TCGv_i64 r_rs2)
 {
     switch (fccno) {
     case 0:
-        gen_helper_fcmpd(cpu_env, r_rs1, r_rs2);
+        gen_helper_fcmpd(cpu_fsr, cpu_env, r_rs1, r_rs2);
         break;
     case 1:
-        gen_helper_fcmpd_fcc1(cpu_env, r_rs1, r_rs2);
+        gen_helper_fcmpd_fcc1(cpu_fsr, cpu_env, r_rs1, r_rs2);
         break;
     case 2:
-        gen_helper_fcmpd_fcc2(cpu_env, r_rs1, r_rs2);
+        gen_helper_fcmpd_fcc2(cpu_fsr, cpu_env, r_rs1, r_rs2);
         break;
     case 3:
-        gen_helper_fcmpd_fcc3(cpu_env, r_rs1, r_rs2);
+        gen_helper_fcmpd_fcc3(cpu_fsr, cpu_env, r_rs1, r_rs2);
         break;
     }
 }
@@ -1533,16 +1561,16 @@ static inline void gen_op_fcmpq(int fccno)
 {
     switch (fccno) {
     case 0:
-        gen_helper_fcmpq(cpu_env);
+        gen_helper_fcmpq(cpu_fsr, cpu_env);
         break;
     case 1:
-        gen_helper_fcmpq_fcc1(cpu_env);
+        gen_helper_fcmpq_fcc1(cpu_fsr, cpu_env);
         break;
     case 2:
-        gen_helper_fcmpq_fcc2(cpu_env);
+        gen_helper_fcmpq_fcc2(cpu_fsr, cpu_env);
         break;
     case 3:
-        gen_helper_fcmpq_fcc3(cpu_env);
+        gen_helper_fcmpq_fcc3(cpu_fsr, cpu_env);
         break;
     }
 }
@@ -1551,16 +1579,16 @@ static inline void gen_op_fcmpes(int fccno, TCGv_i32 r_rs1, TCGv_i32 r_rs2)
 {
     switch (fccno) {
     case 0:
-        gen_helper_fcmpes(cpu_env, r_rs1, r_rs2);
+        gen_helper_fcmpes(cpu_fsr, cpu_env, r_rs1, r_rs2);
         break;
     case 1:
-        gen_helper_fcmpes_fcc1(cpu_env, r_rs1, r_rs2);
+        gen_helper_fcmpes_fcc1(cpu_fsr, cpu_env, r_rs1, r_rs2);
         break;
     case 2:
-        gen_helper_fcmpes_fcc2(cpu_env, r_rs1, r_rs2);
+        gen_helper_fcmpes_fcc2(cpu_fsr, cpu_env, r_rs1, r_rs2);
         break;
     case 3:
-        gen_helper_fcmpes_fcc3(cpu_env, r_rs1, r_rs2);
+        gen_helper_fcmpes_fcc3(cpu_fsr, cpu_env, r_rs1, r_rs2);
         break;
     }
 }
@@ -1569,16 +1597,16 @@ static inline void gen_op_fcmped(int fccno, TCGv_i64 r_rs1, TCGv_i64 r_rs2)
 {
     switch (fccno) {
     case 0:
-        gen_helper_fcmped(cpu_env, r_rs1, r_rs2);
+        gen_helper_fcmped(cpu_fsr, cpu_env, r_rs1, r_rs2);
         break;
     case 1:
-        gen_helper_fcmped_fcc1(cpu_env, r_rs1, r_rs2);
+        gen_helper_fcmped_fcc1(cpu_fsr, cpu_env, r_rs1, r_rs2);
         break;
     case 2:
-        gen_helper_fcmped_fcc2(cpu_env, r_rs1, r_rs2);
+        gen_helper_fcmped_fcc2(cpu_fsr, cpu_env, r_rs1, r_rs2);
         break;
     case 3:
-        gen_helper_fcmped_fcc3(cpu_env, r_rs1, r_rs2);
+        gen_helper_fcmped_fcc3(cpu_fsr, cpu_env, r_rs1, r_rs2);
         break;
     }
 }
@@ -1587,16 +1615,16 @@ static inline void gen_op_fcmpeq(int fccno)
 {
     switch (fccno) {
     case 0:
-        gen_helper_fcmpeq(cpu_env);
+        gen_helper_fcmpeq(cpu_fsr, cpu_env);
         break;
     case 1:
-        gen_helper_fcmpeq_fcc1(cpu_env);
+        gen_helper_fcmpeq_fcc1(cpu_fsr, cpu_env);
         break;
     case 2:
-        gen_helper_fcmpeq_fcc2(cpu_env);
+        gen_helper_fcmpeq_fcc2(cpu_fsr, cpu_env);
         break;
     case 3:
-        gen_helper_fcmpeq_fcc3(cpu_env);
+        gen_helper_fcmpeq_fcc3(cpu_fsr, cpu_env);
         break;
     }
 }
@@ -1605,57 +1633,47 @@ static inline void gen_op_fcmpeq(int fccno)
 
 static inline void gen_op_fcmps(int fccno, TCGv r_rs1, TCGv r_rs2)
 {
-    gen_helper_fcmps(cpu_env, r_rs1, r_rs2);
+    gen_helper_fcmps(cpu_fsr, cpu_env, r_rs1, r_rs2);
 }
 
 static inline void gen_op_fcmpd(int fccno, TCGv_i64 r_rs1, TCGv_i64 r_rs2)
 {
-    gen_helper_fcmpd(cpu_env, r_rs1, r_rs2);
+    gen_helper_fcmpd(cpu_fsr, cpu_env, r_rs1, r_rs2);
 }
 
 static inline void gen_op_fcmpq(int fccno)
 {
-    gen_helper_fcmpq(cpu_env);
+    gen_helper_fcmpq(cpu_fsr, cpu_env);
 }
 
 static inline void gen_op_fcmpes(int fccno, TCGv r_rs1, TCGv r_rs2)
 {
-    gen_helper_fcmpes(cpu_env, r_rs1, r_rs2);
+    gen_helper_fcmpes(cpu_fsr, cpu_env, r_rs1, r_rs2);
 }
 
 static inline void gen_op_fcmped(int fccno, TCGv_i64 r_rs1, TCGv_i64 r_rs2)
 {
-    gen_helper_fcmped(cpu_env, r_rs1, r_rs2);
+    gen_helper_fcmped(cpu_fsr, cpu_env, r_rs1, r_rs2);
 }
 
 static inline void gen_op_fcmpeq(int fccno)
 {
-    gen_helper_fcmpeq(cpu_env);
+    gen_helper_fcmpeq(cpu_fsr, cpu_env);
 }
 #endif
 
-static inline void gen_op_fpexception_im(int fsr_flags)
+static void gen_op_fpexception_im(DisasContext *dc, int fsr_flags)
 {
-    TCGv_i32 r_const;
-
     tcg_gen_andi_tl(cpu_fsr, cpu_fsr, FSR_FTT_NMASK);
     tcg_gen_ori_tl(cpu_fsr, cpu_fsr, fsr_flags);
-    r_const = tcg_const_i32(TT_FP_EXCP);
-    gen_helper_raise_exception(cpu_env, r_const);
-    tcg_temp_free_i32(r_const);
+    gen_exception(dc, TT_FP_EXCP);
 }
 
 static int gen_trap_ifnofpu(DisasContext *dc)
 {
 #if !defined(CONFIG_USER_ONLY)
     if (!dc->fpu_enabled) {
-        TCGv_i32 r_const;
-
-        save_state(dc);
-        r_const = tcg_const_i32(TT_NFPU_INSN);
-        gen_helper_raise_exception(cpu_env, r_const);
-        tcg_temp_free_i32(r_const);
-        dc->is_br = 1;
+        gen_exception(dc, TT_NFPU_INSN);
         return 1;
     }
 #endif
@@ -1676,6 +1694,7 @@ static inline void gen_fop_FF(DisasContext *dc, int rd, int rs,
     dst = gen_dest_fpr_F(dc);
 
     gen(dst, cpu_env, src);
+    gen_helper_check_ieee_exceptions(cpu_fsr, cpu_env);
 
     gen_store_fpr_F(dc, rd, dst);
 }
@@ -1703,6 +1722,7 @@ static inline void gen_fop_FFF(DisasContext *dc, int rd, int rs1, int rs2,
     dst = gen_dest_fpr_F(dc);
 
     gen(dst, cpu_env, src1, src2);
+    gen_helper_check_ieee_exceptions(cpu_fsr, cpu_env);
 
     gen_store_fpr_F(dc, rd, dst);
 }
@@ -1732,6 +1752,7 @@ static inline void gen_fop_DD(DisasContext *dc, int rd, int rs,
     dst = gen_dest_fpr_D(dc, rd);
 
     gen(dst, cpu_env, src);
+    gen_helper_check_ieee_exceptions(cpu_fsr, cpu_env);
 
     gen_store_fpr_D(dc, rd, dst);
 }
@@ -1761,6 +1782,7 @@ static inline void gen_fop_DDD(DisasContext *dc, int rd, int rs1, int rs2,
     dst = gen_dest_fpr_D(dc, rd);
 
     gen(dst, cpu_env, src1, src2);
+    gen_helper_check_ieee_exceptions(cpu_fsr, cpu_env);
 
     gen_store_fpr_D(dc, rd, dst);
 }
@@ -1816,9 +1838,10 @@ static inline void gen_fop_QQ(DisasContext *dc, int rd, int rs,
     gen_op_load_fpr_QT1(QFPREG(rs));
 
     gen(cpu_env);
+    gen_helper_check_ieee_exceptions(cpu_fsr, cpu_env);
 
     gen_op_store_QT0_fpr(QFPREG(rd));
-    gen_update_fprs_dirty(QFPREG(rd));
+    gen_update_fprs_dirty(dc, QFPREG(rd));
 }
 
 #ifdef TARGET_SPARC64
@@ -1830,7 +1853,7 @@ static inline void gen_ne_fop_QQ(DisasContext *dc, int rd, int rs,
     gen(cpu_env);
 
     gen_op_store_QT0_fpr(QFPREG(rd));
-    gen_update_fprs_dirty(QFPREG(rd));
+    gen_update_fprs_dirty(dc, QFPREG(rd));
 }
 #endif
 
@@ -1841,9 +1864,10 @@ static inline void gen_fop_QQQ(DisasContext *dc, int rd, int rs1, int rs2,
     gen_op_load_fpr_QT1(QFPREG(rs2));
 
     gen(cpu_env);
+    gen_helper_check_ieee_exceptions(cpu_fsr, cpu_env);
 
     gen_op_store_QT0_fpr(QFPREG(rd));
-    gen_update_fprs_dirty(QFPREG(rd));
+    gen_update_fprs_dirty(dc, QFPREG(rd));
 }
 
 static inline void gen_fop_DFF(DisasContext *dc, int rd, int rs1, int rs2,
@@ -1857,6 +1881,7 @@ static inline void gen_fop_DFF(DisasContext *dc, int rd, int rs1, int rs2,
     dst = gen_dest_fpr_D(dc, rd);
 
     gen(dst, cpu_env, src1, src2);
+    gen_helper_check_ieee_exceptions(cpu_fsr, cpu_env);
 
     gen_store_fpr_D(dc, rd, dst);
 }
@@ -1870,9 +1895,10 @@ static inline void gen_fop_QDD(DisasContext *dc, int rd, int rs1, int rs2,
     src2 = gen_load_fpr_D(dc, rs2);
 
     gen(cpu_env, src1, src2);
+    gen_helper_check_ieee_exceptions(cpu_fsr, cpu_env);
 
     gen_op_store_QT0_fpr(QFPREG(rd));
-    gen_update_fprs_dirty(QFPREG(rd));
+    gen_update_fprs_dirty(dc, QFPREG(rd));
 }
 
 #ifdef TARGET_SPARC64
@@ -1886,6 +1912,7 @@ static inline void gen_fop_DF(DisasContext *dc, int rd, int rs,
     dst = gen_dest_fpr_D(dc, rd);
 
     gen(dst, cpu_env, src);
+    gen_helper_check_ieee_exceptions(cpu_fsr, cpu_env);
 
     gen_store_fpr_D(dc, rd, dst);
 }
@@ -1915,6 +1942,7 @@ static inline void gen_fop_FD(DisasContext *dc, int rd, int rs,
     dst = gen_dest_fpr_F(dc);
 
     gen(dst, cpu_env, src);
+    gen_helper_check_ieee_exceptions(cpu_fsr, cpu_env);
 
     gen_store_fpr_F(dc, rd, dst);
 }
@@ -1928,6 +1956,7 @@ static inline void gen_fop_FQ(DisasContext *dc, int rd, int rs,
     dst = gen_dest_fpr_F(dc);
 
     gen(dst, cpu_env);
+    gen_helper_check_ieee_exceptions(cpu_fsr, cpu_env);
 
     gen_store_fpr_F(dc, rd, dst);
 }
@@ -1941,6 +1970,7 @@ static inline void gen_fop_DQ(DisasContext *dc, int rd, int rs,
     dst = gen_dest_fpr_D(dc, rd);
 
     gen(dst, cpu_env);
+    gen_helper_check_ieee_exceptions(cpu_fsr, cpu_env);
 
     gen_store_fpr_D(dc, rd, dst);
 }
@@ -1955,7 +1985,7 @@ static inline void gen_ne_fop_QF(DisasContext *dc, int rd, int rs,
     gen(cpu_env, src);
 
     gen_op_store_QT0_fpr(QFPREG(rd));
-    gen_update_fprs_dirty(QFPREG(rd));
+    gen_update_fprs_dirty(dc, QFPREG(rd));
 }
 
 static inline void gen_ne_fop_QD(DisasContext *dc, int rd, int rs,
@@ -1968,266 +1998,734 @@ static inline void gen_ne_fop_QD(DisasContext *dc, int rd, int rs,
     gen(cpu_env, src);
 
     gen_op_store_QT0_fpr(QFPREG(rd));
-    gen_update_fprs_dirty(QFPREG(rd));
+    gen_update_fprs_dirty(dc, QFPREG(rd));
 }
 
 /* asi moves */
-#ifdef TARGET_SPARC64
-static inline TCGv_i32 gen_get_asi(int insn, TCGv r_addr)
-{
+#if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64)
+typedef enum {
+    GET_ASI_HELPER,
+    GET_ASI_EXCP,
+    GET_ASI_DIRECT,
+    GET_ASI_DTWINX,
+    GET_ASI_BLOCK,
+    GET_ASI_SHORT,
+} ASIType;
+
+typedef struct {
+    ASIType type;
     int asi;
-    TCGv_i32 r_asi;
+    int mem_idx;
+    TCGMemOp memop;
+} DisasASI;
+
+static DisasASI get_asi(DisasContext *dc, int insn, TCGMemOp memop)
+{
+    int asi = GET_FIELD(insn, 19, 26);
+    ASIType type = GET_ASI_HELPER;
+    int mem_idx = dc->mem_idx;
 
+#ifndef TARGET_SPARC64
+    /* Before v9, all asis are immediate and privileged.  */
     if (IS_IMM) {
-        r_asi = tcg_temp_new_i32();
-        tcg_gen_mov_i32(r_asi, cpu_asi);
+        gen_exception(dc, TT_ILL_INSN);
+        type = GET_ASI_EXCP;
+    } else if (supervisor(dc)
+               /* Note that LEON accepts ASI_USERDATA in user mode, for
+                  use with CASA.  Also note that previous versions of
+                  QEMU allowed (and old versions of gcc emitted) ASI_P
+                  for LEON, which is incorrect.  */
+               || (asi == ASI_USERDATA
+                   && (dc->def->features & CPU_FEATURE_CASA))) {
+        switch (asi) {
+        case ASI_USERDATA:   /* User data access */
+            mem_idx = MMU_USER_IDX;
+            type = GET_ASI_DIRECT;
+            break;
+        case ASI_KERNELDATA: /* Supervisor data access */
+            mem_idx = MMU_KERNEL_IDX;
+            type = GET_ASI_DIRECT;
+            break;
+        }
     } else {
-        asi = GET_FIELD(insn, 19, 26);
-        r_asi = tcg_const_i32(asi);
+        gen_exception(dc, TT_PRIV_INSN);
+        type = GET_ASI_EXCP;
+    }
+#else
+    if (IS_IMM) {
+        asi = dc->asi;
     }
-    return r_asi;
+    /* With v9, all asis below 0x80 are privileged.  */
+    /* ??? We ought to check cpu_has_hypervisor, but we didn't copy
+       down that bit into DisasContext.  For the moment that's ok,
+       since the direct implementations below doesn't have any ASIs
+       in the restricted [0x30, 0x7f] range, and the check will be
+       done properly in the helper.  */
+    if (!supervisor(dc) && asi < 0x80) {
+        gen_exception(dc, TT_PRIV_ACT);
+        type = GET_ASI_EXCP;
+    } else {
+        switch (asi) {
+        case ASI_N:  /* Nucleus */
+        case ASI_NL: /* Nucleus LE */
+        case ASI_TWINX_N:
+        case ASI_TWINX_NL:
+            mem_idx = MMU_NUCLEUS_IDX;
+            break;
+        case ASI_AIUP:  /* As if user primary */
+        case ASI_AIUPL: /* As if user primary LE */
+        case ASI_TWINX_AIUP:
+        case ASI_TWINX_AIUP_L:
+        case ASI_BLK_AIUP_4V:
+        case ASI_BLK_AIUP_L_4V:
+        case ASI_BLK_AIUP:
+        case ASI_BLK_AIUPL:
+            mem_idx = MMU_USER_IDX;
+            break;
+        case ASI_AIUS:  /* As if user secondary */
+        case ASI_AIUSL: /* As if user secondary LE */
+        case ASI_TWINX_AIUS:
+        case ASI_TWINX_AIUS_L:
+        case ASI_BLK_AIUS_4V:
+        case ASI_BLK_AIUS_L_4V:
+        case ASI_BLK_AIUS:
+        case ASI_BLK_AIUSL:
+            mem_idx = MMU_USER_SECONDARY_IDX;
+            break;
+        case ASI_S:  /* Secondary */
+        case ASI_SL: /* Secondary LE */
+        case ASI_TWINX_S:
+        case ASI_TWINX_SL:
+        case ASI_BLK_COMMIT_S:
+        case ASI_BLK_S:
+        case ASI_BLK_SL:
+        case ASI_FL8_S:
+        case ASI_FL8_SL:
+        case ASI_FL16_S:
+        case ASI_FL16_SL:
+            if (mem_idx == MMU_USER_IDX) {
+                mem_idx = MMU_USER_SECONDARY_IDX;
+            } else if (mem_idx == MMU_KERNEL_IDX) {
+                mem_idx = MMU_KERNEL_SECONDARY_IDX;
+            }
+            break;
+        case ASI_P:  /* Primary */
+        case ASI_PL: /* Primary LE */
+        case ASI_TWINX_P:
+        case ASI_TWINX_PL:
+        case ASI_BLK_COMMIT_P:
+        case ASI_BLK_P:
+        case ASI_BLK_PL:
+        case ASI_FL8_P:
+        case ASI_FL8_PL:
+        case ASI_FL16_P:
+        case ASI_FL16_PL:
+            break;
+        }
+        switch (asi) {
+        case ASI_N:
+        case ASI_NL:
+        case ASI_AIUP:
+        case ASI_AIUPL:
+        case ASI_AIUS:
+        case ASI_AIUSL:
+        case ASI_S:
+        case ASI_SL:
+        case ASI_P:
+        case ASI_PL:
+            type = GET_ASI_DIRECT;
+            break;
+        case ASI_TWINX_N:
+        case ASI_TWINX_NL:
+        case ASI_TWINX_AIUP:
+        case ASI_TWINX_AIUP_L:
+        case ASI_TWINX_AIUS:
+        case ASI_TWINX_AIUS_L:
+        case ASI_TWINX_P:
+        case ASI_TWINX_PL:
+        case ASI_TWINX_S:
+        case ASI_TWINX_SL:
+            type = GET_ASI_DTWINX;
+            break;
+        case ASI_BLK_COMMIT_P:
+        case ASI_BLK_COMMIT_S:
+        case ASI_BLK_AIUP_4V:
+        case ASI_BLK_AIUP_L_4V:
+        case ASI_BLK_AIUP:
+        case ASI_BLK_AIUPL:
+        case ASI_BLK_AIUS_4V:
+        case ASI_BLK_AIUS_L_4V:
+        case ASI_BLK_AIUS:
+        case ASI_BLK_AIUSL:
+        case ASI_BLK_S:
+        case ASI_BLK_SL:
+        case ASI_BLK_P:
+        case ASI_BLK_PL:
+            type = GET_ASI_BLOCK;
+            break;
+        case ASI_FL8_S:
+        case ASI_FL8_SL:
+        case ASI_FL8_P:
+        case ASI_FL8_PL:
+            memop = MO_UB;
+            type = GET_ASI_SHORT;
+            break;
+        case ASI_FL16_S:
+        case ASI_FL16_SL:
+        case ASI_FL16_P:
+        case ASI_FL16_PL:
+            memop = MO_TEUW;
+            type = GET_ASI_SHORT;
+            break;
+        }
+        /* The little-endian asis all have bit 3 set.  */
+        if (asi & 8) {
+            memop ^= MO_BSWAP;
+        }
+    }
+#endif
+
+    return (DisasASI){ type, asi, mem_idx, memop };
 }
 
-static inline void gen_ld_asi(TCGv dst, TCGv addr, int insn, int size,
-                              int sign)
+static void gen_ld_asi(DisasContext *dc, TCGv dst, TCGv addr,
+                       int insn, TCGMemOp memop)
 {
-    TCGv_i32 r_asi, r_size, r_sign;
+    DisasASI da = get_asi(dc, insn, memop);
 
-    r_asi = gen_get_asi(insn, addr);
-    r_size = tcg_const_i32(size);
-    r_sign = tcg_const_i32(sign);
-    gen_helper_ld_asi(dst, cpu_env, addr, r_asi, r_size, r_sign);
-    tcg_temp_free_i32(r_sign);
-    tcg_temp_free_i32(r_size);
-    tcg_temp_free_i32(r_asi);
+    switch (da.type) {
+    case GET_ASI_EXCP:
+        break;
+    case GET_ASI_DTWINX: /* Reserved for ldda.  */
+        gen_exception(dc, TT_ILL_INSN);
+        break;
+    case GET_ASI_DIRECT:
+        gen_address_mask(dc, addr);
+        tcg_gen_qemu_ld_tl(dst, addr, da.mem_idx, da.memop);
+        break;
+    default:
+        {
+            TCGv_i32 r_asi = tcg_const_i32(da.asi);
+            TCGv_i32 r_mop = tcg_const_i32(memop);
+
+            save_state(dc);
+#ifdef TARGET_SPARC64
+            gen_helper_ld_asi(dst, cpu_env, addr, r_asi, r_mop);
+#else
+            {
+                TCGv_i64 t64 = tcg_temp_new_i64();
+                gen_helper_ld_asi(t64, cpu_env, addr, r_asi, r_mop);
+                tcg_gen_trunc_i64_tl(dst, t64);
+                tcg_temp_free_i64(t64);
+            }
+#endif
+            tcg_temp_free_i32(r_mop);
+            tcg_temp_free_i32(r_asi);
+        }
+        break;
+    }
 }
 
-static inline void gen_st_asi(TCGv src, TCGv addr, int insn, int size)
+static void gen_st_asi(DisasContext *dc, TCGv src, TCGv addr,
+                       int insn, TCGMemOp memop)
 {
-    TCGv_i32 r_asi, r_size;
+    DisasASI da = get_asi(dc, insn, memop);
 
-    r_asi = gen_get_asi(insn, addr);
-    r_size = tcg_const_i32(size);
-    gen_helper_st_asi(cpu_env, addr, src, r_asi, r_size);
-    tcg_temp_free_i32(r_size);
-    tcg_temp_free_i32(r_asi);
+    switch (da.type) {
+    case GET_ASI_EXCP:
+        break;
+    case GET_ASI_DTWINX: /* Reserved for stda.  */
+        gen_exception(dc, TT_ILL_INSN);
+        break;
+    case GET_ASI_DIRECT:
+        gen_address_mask(dc, addr);
+        tcg_gen_qemu_st_tl(src, addr, da.mem_idx, da.memop);
+        break;
+    default:
+        {
+            TCGv_i32 r_asi = tcg_const_i32(da.asi);
+            TCGv_i32 r_mop = tcg_const_i32(memop & MO_SIZE);
+
+            save_state(dc);
+#ifdef TARGET_SPARC64
+            gen_helper_st_asi(cpu_env, addr, src, r_asi, r_mop);
+#else
+            {
+                TCGv_i64 t64 = tcg_temp_new_i64();
+                tcg_gen_extu_tl_i64(t64, src);
+                gen_helper_st_asi(cpu_env, addr, t64, r_asi, r_mop);
+                tcg_temp_free_i64(t64);
+            }
+#endif
+            tcg_temp_free_i32(r_mop);
+            tcg_temp_free_i32(r_asi);
+
+            /* A write to a TLB register may alter page maps.  End the TB. */
+            dc->npc = DYNAMIC_PC;
+        }
+        break;
+    }
 }
 
-static inline void gen_ldf_asi(TCGv addr, int insn, int size, int rd)
+static void gen_swap_asi(DisasContext *dc, TCGv dst, TCGv src,
+                         TCGv addr, int insn)
 {
-    TCGv_i32 r_asi, r_size, r_rd;
+    DisasASI da = get_asi(dc, insn, MO_TEUL);
 
-    r_asi = gen_get_asi(insn, addr);
-    r_size = tcg_const_i32(size);
-    r_rd = tcg_const_i32(rd);
-    gen_helper_ldf_asi(cpu_env, addr, r_asi, r_size, r_rd);
-    tcg_temp_free_i32(r_rd);
-    tcg_temp_free_i32(r_size);
-    tcg_temp_free_i32(r_asi);
+    switch (da.type) {
+    case GET_ASI_EXCP:
+        break;
+    default:
+        {
+            TCGv_i32 r_asi = tcg_const_i32(da.asi);
+            TCGv_i32 r_mop = tcg_const_i32(MO_UL);
+            TCGv_i64 s64, t64;
+
+            save_state(dc);
+            t64 = tcg_temp_new_i64();
+            gen_helper_ld_asi(t64, cpu_env, addr, r_asi, r_mop);
+
+            s64 = tcg_temp_new_i64();
+            tcg_gen_extu_tl_i64(s64, src);
+            gen_helper_st_asi(cpu_env, addr, s64, r_asi, r_mop);
+            tcg_temp_free_i64(s64);
+            tcg_temp_free_i32(r_mop);
+            tcg_temp_free_i32(r_asi);
+
+            tcg_gen_trunc_i64_tl(dst, t64);
+            tcg_temp_free_i64(t64);
+        }
+        break;
+    }
 }
 
-static inline void gen_stf_asi(TCGv addr, int insn, int size, int rd)
+static void gen_cas_asi(DisasContext *dc, TCGv addr, TCGv val2,
+                        int insn, int rd)
 {
-    TCGv_i32 r_asi, r_size, r_rd;
+    DisasASI da = get_asi(dc, insn, MO_TEUL);
+    TCGv val1, dst;
+    TCGv_i32 r_asi;
 
-    r_asi = gen_get_asi(insn, addr);
-    r_size = tcg_const_i32(size);
-    r_rd = tcg_const_i32(rd);
-    gen_helper_stf_asi(cpu_env, addr, r_asi, r_size, r_rd);
-    tcg_temp_free_i32(r_rd);
-    tcg_temp_free_i32(r_size);
+    if (da.type == GET_ASI_EXCP) {
+        return;
+    }
+
+    save_state(dc);
+    val1 = gen_load_gpr(dc, rd);
+    dst = gen_dest_gpr(dc, rd);
+    r_asi = tcg_const_i32(da.asi);
+    gen_helper_cas_asi(dst, cpu_env, addr, val1, val2, r_asi);
     tcg_temp_free_i32(r_asi);
+    gen_store_gpr(dc, rd, dst);
 }
 
-static inline void gen_swap_asi(TCGv dst, TCGv src, TCGv addr, int insn)
+static void gen_ldstub_asi(DisasContext *dc, TCGv dst, TCGv addr, int insn)
 {
-    TCGv_i32 r_asi, r_size, r_sign;
-    TCGv_i64 t64 = tcg_temp_new_i64();
+    DisasASI da = get_asi(dc, insn, MO_UB);
 
-    r_asi = gen_get_asi(insn, addr);
-    r_size = tcg_const_i32(4);
-    r_sign = tcg_const_i32(0);
-    gen_helper_ld_asi(t64, cpu_env, addr, r_asi, r_size, r_sign);
-    tcg_temp_free_i32(r_sign);
-    gen_helper_st_asi(cpu_env, addr, src, r_asi, r_size);
-    tcg_temp_free_i32(r_size);
-    tcg_temp_free_i32(r_asi);
-    tcg_gen_trunc_i64_tl(dst, t64);
-    tcg_temp_free_i64(t64);
+    switch (da.type) {
+    case GET_ASI_EXCP:
+        break;
+    default:
+        {
+            TCGv_i32 r_asi = tcg_const_i32(da.asi);
+            TCGv_i32 r_mop = tcg_const_i32(MO_UB);
+            TCGv_i64 s64, t64;
+
+            save_state(dc);
+            t64 = tcg_temp_new_i64();
+            gen_helper_ld_asi(t64, cpu_env, addr, r_asi, r_mop);
+
+            s64 = tcg_const_i64(0xff);
+            gen_helper_st_asi(cpu_env, addr, s64, r_asi, r_mop);
+            tcg_temp_free_i64(s64);
+            tcg_temp_free_i32(r_mop);
+            tcg_temp_free_i32(r_asi);
+
+            tcg_gen_trunc_i64_tl(dst, t64);
+            tcg_temp_free_i64(t64);
+        }
+        break;
+    }
 }
+#endif
 
-static inline void gen_ldda_asi(DisasContext *dc, TCGv hi, TCGv addr,
-                                int insn, int rd)
+#ifdef TARGET_SPARC64
+static void gen_ldf_asi(DisasContext *dc, TCGv addr,
+                        int insn, int size, int rd)
 {
-    TCGv_i32 r_asi, r_rd;
+    DisasASI da = get_asi(dc, insn, (size == 4 ? MO_TEUL : MO_TEQ));
+    TCGv_i32 d32;
 
-    r_asi = gen_get_asi(insn, addr);
-    r_rd = tcg_const_i32(rd);
-    gen_helper_ldda_asi(cpu_env, addr, r_asi, r_rd);
-    tcg_temp_free_i32(r_rd);
-    tcg_temp_free_i32(r_asi);
+    switch (da.type) {
+    case GET_ASI_EXCP:
+        break;
+
+    case GET_ASI_DIRECT:
+        gen_address_mask(dc, addr);
+        switch (size) {
+        case 4:
+            d32 = gen_dest_fpr_F(dc);
+            tcg_gen_qemu_ld_i32(d32, addr, da.mem_idx, da.memop);
+            gen_store_fpr_F(dc, rd, d32);
+            break;
+        case 8:
+            tcg_gen_qemu_ld_i64(cpu_fpr[rd / 2], addr, da.mem_idx, da.memop);
+            break;
+        case 16:
+            tcg_gen_qemu_ld_i64(cpu_fpr[rd / 2], addr, da.mem_idx, da.memop);
+            tcg_gen_addi_tl(addr, addr, 8);
+            tcg_gen_qemu_ld_i64(cpu_fpr[rd/2+1], addr, da.mem_idx, da.memop);
+            break;
+        default:
+            g_assert_not_reached();
+        }
+        break;
+
+    case GET_ASI_BLOCK:
+        /* Valid for lddfa on aligned registers only.  */
+        if (size == 8 && (rd & 7) == 0) {
+            TCGv eight;
+            int i;
+
+            gen_check_align(addr, 0x3f);
+            gen_address_mask(dc, addr);
+
+            eight = tcg_const_tl(8);
+            for (i = 0; ; ++i) {
+                tcg_gen_qemu_ld_i64(cpu_fpr[rd / 2 + i], addr,
+                                    da.mem_idx, da.memop);
+                if (i == 7) {
+                    break;
+                }
+                tcg_gen_add_tl(addr, addr, eight);
+            }
+            tcg_temp_free(eight);
+        } else {
+            gen_exception(dc, TT_ILL_INSN);
+        }
+        break;
+
+    case GET_ASI_SHORT:
+        /* Valid for lddfa only.  */
+        if (size == 8) {
+            gen_address_mask(dc, addr);
+            tcg_gen_qemu_ld_i64(cpu_fpr[rd / 2], addr, da.mem_idx, da.memop);
+        } else {
+            gen_exception(dc, TT_ILL_INSN);
+        }
+        break;
+
+    default:
+        {
+            TCGv_i32 r_asi = tcg_const_i32(da.asi);
+            TCGv_i32 r_mop = tcg_const_i32(da.memop);
+
+            save_state(dc);
+            /* According to the table in the UA2011 manual, the only
+               other asis that are valid for ldfa/lddfa/ldqfa are
+               the NO_FAULT asis.  We still need a helper for these,
+               but we can just use the integer asi helper for them.  */
+            switch (size) {
+            case 4:
+                {
+                    TCGv d64 = tcg_temp_new_i64();
+                    gen_helper_ld_asi(d64, cpu_env, addr, r_asi, r_mop);
+                    d32 = gen_dest_fpr_F(dc);
+                    tcg_gen_extrl_i64_i32(d32, d64);
+                    tcg_temp_free_i64(d64);
+                    gen_store_fpr_F(dc, rd, d32);
+                }
+                break;
+            case 8:
+                gen_helper_ld_asi(cpu_fpr[rd / 2], cpu_env, addr, r_asi, r_mop);
+                break;
+            case 16:
+                gen_helper_ld_asi(cpu_fpr[rd / 2], cpu_env, addr, r_asi, r_mop);
+                tcg_gen_addi_tl(addr, addr, 8);
+                gen_helper_ld_asi(cpu_fpr[rd/2+1], cpu_env, addr, r_asi, r_mop);
+                break;
+            default:
+                g_assert_not_reached();
+            }
+            tcg_temp_free_i32(r_mop);
+            tcg_temp_free_i32(r_asi);
+        }
+        break;
+    }
 }
 
-static inline void gen_stda_asi(DisasContext *dc, TCGv hi, TCGv addr,
-                                int insn, int rd)
+static void gen_stf_asi(DisasContext *dc, TCGv addr,
+                        int insn, int size, int rd)
 {
-    TCGv_i32 r_asi, r_size;
-    TCGv lo = gen_load_gpr(dc, rd + 1);
-    TCGv_i64 t64 = tcg_temp_new_i64();
+    DisasASI da = get_asi(dc, insn, (size == 4 ? MO_TEUL : MO_TEQ));
+    TCGv_i32 d32;
 
-    tcg_gen_concat_tl_i64(t64, lo, hi);
-    r_asi = gen_get_asi(insn, addr);
-    r_size = tcg_const_i32(8);
-    gen_helper_st_asi(cpu_env, addr, t64, r_asi, r_size);
-    tcg_temp_free_i32(r_size);
-    tcg_temp_free_i32(r_asi);
-    tcg_temp_free_i64(t64);
+    switch (da.type) {
+    case GET_ASI_EXCP:
+        break;
+
+    case GET_ASI_DIRECT:
+        gen_address_mask(dc, addr);
+        switch (size) {
+        case 4:
+            d32 = gen_load_fpr_F(dc, rd);
+            tcg_gen_qemu_st_i32(d32, addr, da.mem_idx, da.memop);
+            break;
+        case 8:
+            tcg_gen_qemu_st_i64(cpu_fpr[rd / 2], addr, da.mem_idx, da.memop);
+            break;
+        case 16:
+            tcg_gen_qemu_st_i64(cpu_fpr[rd / 2], addr, da.mem_idx, da.memop);
+            tcg_gen_addi_tl(addr, addr, 8);
+            tcg_gen_qemu_st_i64(cpu_fpr[rd/2+1], addr, da.mem_idx, da.memop);
+            break;
+        default:
+            g_assert_not_reached();
+        }
+        break;
+
+    case GET_ASI_BLOCK:
+        /* Valid for stdfa on aligned registers only.  */
+        if (size == 8 && (rd & 7) == 0) {
+            TCGv eight;
+            int i;
+
+            gen_check_align(addr, 0x3f);
+            gen_address_mask(dc, addr);
+
+            eight = tcg_const_tl(8);
+            for (i = 0; ; ++i) {
+                tcg_gen_qemu_st_i64(cpu_fpr[rd / 2 + i], addr,
+                                    da.mem_idx, da.memop);
+                if (i == 7) {
+                    break;
+                }
+                tcg_gen_add_tl(addr, addr, eight);
+            }
+            tcg_temp_free(eight);
+        } else {
+            gen_exception(dc, TT_ILL_INSN);
+        }
+        break;
+
+    case GET_ASI_SHORT:
+        /* Valid for stdfa only.  */
+        if (size == 8) {
+            gen_address_mask(dc, addr);
+            tcg_gen_qemu_st_i64(cpu_fpr[rd / 2], addr, da.mem_idx, da.memop);
+        } else {
+            gen_exception(dc, TT_ILL_INSN);
+        }
+        break;
+
+    default:
+        /* According to the table in the UA2011 manual, the only
+           other asis that are valid for ldfa/lddfa/ldqfa are
+           the PST* asis, which aren't currently handled.  */
+        gen_exception(dc, TT_ILL_INSN);
+        break;
+    }
 }
 
-static inline void gen_casx_asi(DisasContext *dc, TCGv addr,
-                                TCGv val2, int insn, int rd)
+static void gen_ldda_asi(DisasContext *dc, TCGv addr, int insn, int rd)
 {
-    TCGv val1 = gen_load_gpr(dc, rd);
-    TCGv dst = gen_dest_gpr(dc, rd);
-    TCGv_i32 r_asi = gen_get_asi(insn, addr);
+    DisasASI da = get_asi(dc, insn, MO_TEQ);
+    TCGv_i64 hi = gen_dest_gpr(dc, rd);
+    TCGv_i64 lo = gen_dest_gpr(dc, rd + 1);
 
-    gen_helper_casx_asi(dst, cpu_env, addr, val1, val2, r_asi);
-    tcg_temp_free_i32(r_asi);
-    gen_store_gpr(dc, rd, dst);
-}
+    switch (da.type) {
+    case GET_ASI_EXCP:
+        return;
 
-#elif !defined(CONFIG_USER_ONLY)
+    case GET_ASI_DTWINX:
+        gen_check_align(addr, 15);
+        gen_address_mask(dc, addr);
+        tcg_gen_qemu_ld_i64(hi, addr, da.mem_idx, da.memop);
+        tcg_gen_addi_tl(addr, addr, 8);
+        tcg_gen_qemu_ld_i64(lo, addr, da.mem_idx, da.memop);
+        break;
 
-static inline void gen_ld_asi(TCGv dst, TCGv addr, int insn, int size,
-                              int sign)
-{
-    TCGv_i32 r_asi, r_size, r_sign;
-    TCGv_i64 t64 = tcg_temp_new_i64();
+    case GET_ASI_DIRECT:
+        {
+            TCGv_i64 tmp = tcg_temp_new_i64();
 
-    r_asi = tcg_const_i32(GET_FIELD(insn, 19, 26));
-    r_size = tcg_const_i32(size);
-    r_sign = tcg_const_i32(sign);
-    gen_helper_ld_asi(t64, cpu_env, addr, r_asi, r_size, r_sign);
-    tcg_temp_free_i32(r_sign);
-    tcg_temp_free_i32(r_size);
-    tcg_temp_free_i32(r_asi);
-    tcg_gen_trunc_i64_tl(dst, t64);
-    tcg_temp_free_i64(t64);
+            gen_address_mask(dc, addr);
+            tcg_gen_qemu_ld_i64(tmp, addr, da.mem_idx, da.memop);
+
+            /* Note that LE ldda acts as if each 32-bit register
+               result is byte swapped.  Having just performed one
+               64-bit bswap, we need now to swap the writebacks.  */
+            if ((da.memop & MO_BSWAP) == MO_TE) {
+                tcg_gen_extr32_i64(lo, hi, tmp);
+            } else {
+                tcg_gen_extr32_i64(hi, lo, tmp);
+            }
+            tcg_temp_free_i64(tmp);
+        }
+        break;
+
+    default:
+        {
+            TCGv_i32 r_asi = tcg_const_i32(da.asi);
+
+            save_state(dc);
+            gen_helper_ldda_asi(cpu_env, addr, r_asi);
+            tcg_temp_free_i32(r_asi);
+
+            tcg_gen_ld_i64(hi, cpu_env, offsetof(CPUSPARCState, qt0.high));
+            tcg_gen_ld_i64(lo, cpu_env, offsetof(CPUSPARCState, qt0.low));
+        }
+        break;
+    }
+
+    gen_store_gpr(dc, rd, hi);
+    gen_store_gpr(dc, rd + 1, lo);
 }
 
-static inline void gen_st_asi(TCGv src, TCGv addr, int insn, int size)
+static void gen_stda_asi(DisasContext *dc, TCGv hi, TCGv addr,
+                         int insn, int rd)
 {
-    TCGv_i32 r_asi, r_size;
-    TCGv_i64 t64 = tcg_temp_new_i64();
+    DisasASI da = get_asi(dc, insn, MO_TEQ);
+    TCGv lo = gen_load_gpr(dc, rd + 1);
 
-    tcg_gen_extu_tl_i64(t64, src);
-    r_asi = tcg_const_i32(GET_FIELD(insn, 19, 26));
-    r_size = tcg_const_i32(size);
-    gen_helper_st_asi(cpu_env, addr, t64, r_asi, r_size);
-    tcg_temp_free_i32(r_size);
-    tcg_temp_free_i32(r_asi);
-    tcg_temp_free_i64(t64);
+    switch (da.type) {
+    case GET_ASI_EXCP:
+        break;
+
+    case GET_ASI_DTWINX:
+        gen_check_align(addr, 15);
+        gen_address_mask(dc, addr);
+        tcg_gen_qemu_st_i64(hi, addr, da.mem_idx, da.memop);
+        tcg_gen_addi_tl(addr, addr, 8);
+        tcg_gen_qemu_st_i64(lo, addr, da.mem_idx, da.memop);
+        break;
+
+    case GET_ASI_DIRECT:
+        {
+            TCGv_i64 t64 = tcg_temp_new_i64();
+
+            /* Note that LE stda acts as if each 32-bit register result is
+               byte swapped.  We will perform one 64-bit LE store, so now
+               we must swap the order of the construction.  */
+            if ((da.memop & MO_BSWAP) == MO_TE) {
+                tcg_gen_concat32_i64(t64, lo, hi);
+            } else {
+                tcg_gen_concat32_i64(t64, hi, lo);
+            }
+            gen_address_mask(dc, addr);
+            tcg_gen_qemu_st_i64(t64, addr, da.mem_idx, da.memop);
+            tcg_temp_free_i64(t64);
+        }
+        break;
+
+    default:
+        {
+            TCGv_i32 r_asi = tcg_const_i32(da.asi);
+            TCGv_i32 r_mop = tcg_const_i32(MO_Q);
+            TCGv_i64 t64;
+
+            save_state(dc);
+
+            t64 = tcg_temp_new_i64();
+            tcg_gen_concat_tl_i64(t64, lo, hi);
+            gen_helper_st_asi(cpu_env, addr, t64, r_asi, r_mop);
+            tcg_temp_free_i32(r_mop);
+            tcg_temp_free_i32(r_asi);
+            tcg_temp_free_i64(t64);
+        }
+        break;
+    }
 }
 
-static inline void gen_swap_asi(TCGv dst, TCGv src, TCGv addr, int insn)
+static void gen_casx_asi(DisasContext *dc, TCGv addr, TCGv val2,
+                         int insn, int rd)
 {
-    TCGv_i32 r_asi, r_size, r_sign;
-    TCGv_i64 r_val, t64;
+    DisasASI da = get_asi(dc, insn, MO_TEQ);
+    TCGv val1 = gen_load_gpr(dc, rd);
+    TCGv dst = gen_dest_gpr(dc, rd);
+    TCGv_i32 r_asi;
 
-    r_asi = tcg_const_i32(GET_FIELD(insn, 19, 26));
-    r_size = tcg_const_i32(4);
-    r_sign = tcg_const_i32(0);
-    t64 = tcg_temp_new_i64();
-    gen_helper_ld_asi(t64, cpu_env, addr, r_asi, r_size, r_sign);
-    tcg_temp_free(r_sign);
-    r_val = tcg_temp_new_i64();
-    tcg_gen_extu_tl_i64(r_val, src);
-    gen_helper_st_asi(cpu_env, addr, r_val, r_asi, r_size);
-    tcg_temp_free_i64(r_val);
-    tcg_temp_free_i32(r_size);
+    if (da.type == GET_ASI_EXCP) {
+        return;
+    }
+
+    save_state(dc);
+    r_asi = tcg_const_i32(da.asi);
+    gen_helper_casx_asi(dst, cpu_env, addr, val1, val2, r_asi);
     tcg_temp_free_i32(r_asi);
-    tcg_gen_trunc_i64_tl(dst, t64);
-    tcg_temp_free_i64(t64);
+    gen_store_gpr(dc, rd, dst);
 }
 
-static inline void gen_ldda_asi(DisasContext *dc, TCGv hi, TCGv addr,
-                                int insn, int rd)
+#elif !defined(CONFIG_USER_ONLY)
+static void gen_ldda_asi(DisasContext *dc, TCGv addr, int insn, int rd)
 {
-    TCGv_i32 r_asi, r_size, r_sign;
-    TCGv t;
-    TCGv_i64 t64;
-
-    r_asi = tcg_const_i32(GET_FIELD(insn, 19, 26));
-    r_size = tcg_const_i32(8);
-    r_sign = tcg_const_i32(0);
-    t64 = tcg_temp_new_i64();
-    gen_helper_ld_asi(t64, cpu_env, addr, r_asi, r_size, r_sign);
-    tcg_temp_free_i32(r_sign);
-    tcg_temp_free_i32(r_size);
-    tcg_temp_free_i32(r_asi);
-
     /* ??? Work around an apparent bug in Ubuntu gcc 4.8.2-10ubuntu2+12,
        whereby "rd + 1" elicits "error: array subscript is above array".
        Since we have already asserted that rd is even, the semantics
        are unchanged.  */
-    t = gen_dest_gpr(dc, rd | 1);
-    tcg_gen_trunc_i64_tl(t, t64);
-    gen_store_gpr(dc, rd | 1, t);
+    TCGv lo = gen_dest_gpr(dc, rd | 1);
+    TCGv hi = gen_dest_gpr(dc, rd);
+    TCGv_i64 t64 = tcg_temp_new_i64();
+    DisasASI da = get_asi(dc, insn, MO_TEQ);
+
+    switch (da.type) {
+    case GET_ASI_EXCP:
+        tcg_temp_free_i64(t64);
+        return;
+    case GET_ASI_DIRECT:
+        gen_address_mask(dc, addr);
+        tcg_gen_qemu_ld_i64(t64, addr, da.mem_idx, da.memop);
+        break;
+    default:
+        {
+            TCGv_i32 r_asi = tcg_const_i32(da.asi);
+            TCGv_i32 r_mop = tcg_const_i32(MO_Q);
+
+            save_state(dc);
+            gen_helper_ld_asi(t64, cpu_env, addr, r_asi, r_mop);
+            tcg_temp_free_i32(r_mop);
+            tcg_temp_free_i32(r_asi);
+        }
+        break;
+    }
 
-    tcg_gen_shri_i64(t64, t64, 32);
-    tcg_gen_trunc_i64_tl(hi, t64);
+    tcg_gen_extr_i64_i32(lo, hi, t64);
     tcg_temp_free_i64(t64);
+    gen_store_gpr(dc, rd | 1, lo);
     gen_store_gpr(dc, rd, hi);
 }
 
-static inline void gen_stda_asi(DisasContext *dc, TCGv hi, TCGv addr,
-                                int insn, int rd)
+static void gen_stda_asi(DisasContext *dc, TCGv hi, TCGv addr,
+                         int insn, int rd)
 {
-    TCGv_i32 r_asi, r_size;
+    DisasASI da = get_asi(dc, insn, MO_TEQ);
     TCGv lo = gen_load_gpr(dc, rd + 1);
     TCGv_i64 t64 = tcg_temp_new_i64();
 
     tcg_gen_concat_tl_i64(t64, lo, hi);
-    r_asi = tcg_const_i32(GET_FIELD(insn, 19, 26));
-    r_size = tcg_const_i32(8);
-    gen_helper_st_asi(cpu_env, addr, t64, r_asi, r_size);
-    tcg_temp_free_i32(r_size);
-    tcg_temp_free_i32(r_asi);
-    tcg_temp_free_i64(t64);
-}
-#endif
-
-#if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64)
-static inline void gen_cas_asi(DisasContext *dc, TCGv addr,
-                               TCGv val2, int insn, int rd)
-{
-    TCGv val1 = gen_load_gpr(dc, rd);
-    TCGv dst = gen_dest_gpr(dc, rd);
-#ifdef TARGET_SPARC64
-    TCGv_i32 r_asi = gen_get_asi(insn, addr);
-#else
-    TCGv_i32 r_asi = tcg_const_i32(GET_FIELD(insn, 19, 26));
-#endif
 
-    gen_helper_cas_asi(dst, cpu_env, addr, val1, val2, r_asi);
-    tcg_temp_free_i32(r_asi);
-    gen_store_gpr(dc, rd, dst);
-}
-
-static inline void gen_ldstub_asi(TCGv dst, TCGv addr, int insn)
-{
-    TCGv_i64 r_val;
-    TCGv_i32 r_asi, r_size;
+    switch (da.type) {
+    case GET_ASI_EXCP:
+        break;
+    case GET_ASI_DIRECT:
+        gen_address_mask(dc, addr);
+        tcg_gen_qemu_st_i64(t64, addr, da.mem_idx, da.memop);
+        break;
+    default:
+        {
+            TCGv_i32 r_asi = tcg_const_i32(da.asi);
+            TCGv_i32 r_mop = tcg_const_i32(MO_Q);
 
-    gen_ld_asi(dst, addr, insn, 1, 0);
+            save_state(dc);
+            gen_helper_st_asi(cpu_env, addr, t64, r_asi, r_mop);
+            tcg_temp_free_i32(r_mop);
+            tcg_temp_free_i32(r_asi);
+        }
+        break;
+    }
 
-    r_val = tcg_const_i64(0xffULL);
-    r_asi = tcg_const_i32(GET_FIELD(insn, 19, 26));
-    r_size = tcg_const_i32(1);
-    gen_helper_st_asi(cpu_env, addr, r_val, r_asi, r_size);
-    tcg_temp_free_i32(r_size);
-    tcg_temp_free_i32(r_asi);
-    tcg_temp_free_i64(r_val);
+    tcg_temp_free_i64(t64);
 }
 #endif
 
@@ -2299,7 +2797,7 @@ static void gen_fmovq(DisasContext *dc, DisasCompare *cmp, int rd, int rs)
     tcg_gen_movcond_i64(cmp->cond, cpu_fpr[qd / 2 + 1], cmp->c1, cmp->c2,
                         cpu_fpr[qs / 2 + 1], cpu_fpr[qd / 2 + 1]);
 
-    gen_update_fprs_dirty(qd);
+    gen_update_fprs_dirty(dc, qd);
 }
 
 #ifndef CONFIG_USER_ONLY
@@ -2711,7 +3209,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
                     gen_store_gpr(dc, rd, cpu_dst);
                     break;
                 case 0x3: /* V9 rdasi */
-                    tcg_gen_ext_i32_tl(cpu_dst, cpu_asi);
+                    tcg_gen_movi_tl(cpu_dst, dc->asi);
                     gen_store_gpr(dc, rd, cpu_dst);
                     break;
                 case 0x4: /* V9 rdtick */
@@ -2754,7 +3252,8 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
                     gen_store_gpr(dc, rd, cpu_gsr);
                     break;
                 case 0x16: /* Softint */
-                    tcg_gen_ext_i32_tl(cpu_dst, cpu_softint);
+                    tcg_gen_ld32s_tl(cpu_dst, cpu_env,
+                                     offsetof(CPUSPARCState, softint));
                     gen_store_gpr(dc, rd, cpu_dst);
                     break;
                 case 0x17: /* Tick compare */
@@ -2972,7 +3471,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
                 rs1 = GET_FIELD(insn, 13, 17);
                 rs2 = GET_FIELD(insn, 27, 31);
                 xop = GET_FIELD(insn, 18, 26);
-                save_state(dc);
+
                 switch (xop) {
                 case 0x1: /* fmovs */
                     cpu_src1_32 = gen_load_fpr_F(dc, rs2);
@@ -3096,7 +3595,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
                     break;
                 case 0x3: /* V9 fmovq */
                     CHECK_FPU_FEATURE(dc, FLOAT128);
-                    gen_move_Q(rd, rs2);
+                    gen_move_Q(dc, rd, rs2);
                     break;
                 case 0x6: /* V9 fnegd */
                     gen_ne_fop_DD(dc, rd, rs2, gen_helper_fnegd);
@@ -3147,7 +3646,6 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
                 rs1 = GET_FIELD(insn, 13, 17);
                 rs2 = GET_FIELD(insn, 27, 31);
                 xop = GET_FIELD(insn, 18, 26);
-                save_state(dc);
 
 #ifdef TARGET_SPARC64
 #define FMOVR(sz)                                                  \
@@ -3636,11 +4134,18 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
                             case 0x3: /* V9 wrasi */
                                 tcg_gen_xor_tl(cpu_tmp0, cpu_src1, cpu_src2);
                                 tcg_gen_andi_tl(cpu_tmp0, cpu_tmp0, 0xff);
-                                tcg_gen_trunc_tl_i32(cpu_asi, cpu_tmp0);
+                                tcg_gen_st32_tl(cpu_tmp0, cpu_env,
+                                                offsetof(CPUSPARCState, asi));
+                                /* End TB to notice changed ASI.  */
+                                save_state(dc);
+                                gen_op_next_insn();
+                                tcg_gen_exit_tb(0);
+                                dc->is_br = 1;
                                 break;
                             case 0x6: /* V9 wrfprs */
                                 tcg_gen_xor_tl(cpu_tmp0, cpu_src1, cpu_src2);
                                 tcg_gen_trunc_tl_i32(cpu_fprs, cpu_tmp0);
+                                dc->fprs_dirty = 0;
                                 save_state(dc);
                                 gen_op_next_insn();
                                 tcg_gen_exit_tb(0);
@@ -4483,8 +4988,6 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
 #endif
 #ifdef TARGET_SPARC64
             } else if (xop == 0x39) { /* V9 return */
-                TCGv_i32 r_const;
-
                 save_state(dc);
                 cpu_src1 = get_src1(dc, insn);
                 cpu_tmp0 = get_temp_tl(dc);
@@ -4502,9 +5005,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
                 }
                 gen_helper_restore(cpu_env);
                 gen_mov_pc_npc(dc);
-                r_const = tcg_const_i32(3);
-                gen_helper_check_align(cpu_env, cpu_tmp0, r_const);
-                tcg_temp_free_i32(r_const);
+                gen_check_align(cpu_tmp0, 3);
                 tcg_gen_mov_tl(cpu_npc, cpu_tmp0);
                 dc->npc = DYNAMIC_PC;
                 goto jmp_insn;
@@ -4527,16 +5028,12 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
                 switch (xop) {
                 case 0x38:      /* jmpl */
                     {
-                        TCGv t;
-                        TCGv_i32 r_const;
-
-                        t = gen_dest_gpr(dc, rd);
+                        TCGv t = gen_dest_gpr(dc, rd);
                         tcg_gen_movi_tl(t, dc->pc);
                         gen_store_gpr(dc, rd, t);
+
                         gen_mov_pc_npc(dc);
-                        r_const = tcg_const_i32(3);
-                        gen_helper_check_align(cpu_env, cpu_tmp0, r_const);
-                        tcg_temp_free_i32(r_const);
+                        gen_check_align(cpu_tmp0, 3);
                         gen_address_mask(dc, cpu_tmp0);
                         tcg_gen_mov_tl(cpu_npc, cpu_tmp0);
                         dc->npc = DYNAMIC_PC;
@@ -4545,14 +5042,10 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
 #if !defined(CONFIG_USER_ONLY) && !defined(TARGET_SPARC64)
                 case 0x39:      /* rett, V9 return */
                     {
-                        TCGv_i32 r_const;
-
                         if (!supervisor(dc))
                             goto priv_insn;
                         gen_mov_pc_npc(dc);
-                        r_const = tcg_const_i32(3);
-                        gen_helper_check_align(cpu_env, cpu_tmp0, r_const);
-                        tcg_temp_free_i32(r_const);
+                        gen_check_align(cpu_tmp0, 3);
                         tcg_gen_mov_tl(cpu_npc, cpu_tmp0);
                         dc->npc = DYNAMIC_PC;
                         gen_helper_rett(cpu_env);
@@ -4648,14 +5141,8 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
                     if (rd & 1)
                         goto illegal_insn;
                     else {
-                        TCGv_i32 r_const;
                         TCGv_i64 t64;
 
-                        save_state(dc);
-                        r_const = tcg_const_i32(7);
-                        /* XXX remove alignment check */
-                        gen_helper_check_align(cpu_env, cpu_addr, r_const);
-                        tcg_temp_free_i32(r_const);
                         gen_address_mask(dc, cpu_addr);
                         t64 = tcg_temp_new_i64();
                         tcg_gen_qemu_ld64(t64, cpu_addr, dc->mem_idx);
@@ -4704,89 +5191,34 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
                     break;
 #if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64)
                 case 0x10:      /* lda, V9 lduwa, load word alternate */
-#ifndef TARGET_SPARC64
-                    if (IS_IMM)
-                        goto illegal_insn;
-                    if (!supervisor(dc))
-                        goto priv_insn;
-#endif
-                    save_state(dc);
-                    gen_ld_asi(cpu_val, cpu_addr, insn, 4, 0);
+                    gen_ld_asi(dc, cpu_val, cpu_addr, insn, MO_TEUL);
                     break;
                 case 0x11:      /* lduba, load unsigned byte alternate */
-#ifndef TARGET_SPARC64
-                    if (IS_IMM)
-                        goto illegal_insn;
-                    if (!supervisor(dc))
-                        goto priv_insn;
-#endif
-                    save_state(dc);
-                    gen_ld_asi(cpu_val, cpu_addr, insn, 1, 0);
+                    gen_ld_asi(dc, cpu_val, cpu_addr, insn, MO_UB);
                     break;
                 case 0x12:      /* lduha, load unsigned halfword alternate */
-#ifndef TARGET_SPARC64
-                    if (IS_IMM)
-                        goto illegal_insn;
-                    if (!supervisor(dc))
-                        goto priv_insn;
-#endif
-                    save_state(dc);
-                    gen_ld_asi(cpu_val, cpu_addr, insn, 2, 0);
+                    gen_ld_asi(dc, cpu_val, cpu_addr, insn, MO_TEUW);
                     break;
                 case 0x13:      /* ldda, load double word alternate */
-#ifndef TARGET_SPARC64
-                    if (IS_IMM)
-                        goto illegal_insn;
-                    if (!supervisor(dc))
-                        goto priv_insn;
-#endif
-                    if (rd & 1)
+                    if (rd & 1) {
                         goto illegal_insn;
-                    save_state(dc);
-                    gen_ldda_asi(dc, cpu_val, cpu_addr, insn, rd);
+                    }
+                    gen_ldda_asi(dc, cpu_addr, insn, rd);
                     goto skip_move;
                 case 0x19:      /* ldsba, load signed byte alternate */
-#ifndef TARGET_SPARC64
-                    if (IS_IMM)
-                        goto illegal_insn;
-                    if (!supervisor(dc))
-                        goto priv_insn;
-#endif
-                    save_state(dc);
-                    gen_ld_asi(cpu_val, cpu_addr, insn, 1, 1);
+                    gen_ld_asi(dc, cpu_val, cpu_addr, insn, MO_SB);
                     break;
                 case 0x1a:      /* ldsha, load signed halfword alternate */
-#ifndef TARGET_SPARC64
-                    if (IS_IMM)
-                        goto illegal_insn;
-                    if (!supervisor(dc))
-                        goto priv_insn;
-#endif
-                    save_state(dc);
-                    gen_ld_asi(cpu_val, cpu_addr, insn, 2, 1);
+                    gen_ld_asi(dc, cpu_val, cpu_addr, insn, MO_TESW);
                     break;
                 case 0x1d:      /* ldstuba -- XXX: should be atomically */
-#ifndef TARGET_SPARC64
-                    if (IS_IMM)
-                        goto illegal_insn;
-                    if (!supervisor(dc))
-                        goto priv_insn;
-#endif
-                    save_state(dc);
-                    gen_ldstub_asi(cpu_val, cpu_addr, insn);
+                    gen_ldstub_asi(dc, cpu_val, cpu_addr, insn);
                     break;
                 case 0x1f:      /* swapa, swap reg with alt. memory. Also
                                    atomically */
                     CHECK_IU_FEATURE(dc, SWAP);
-#ifndef TARGET_SPARC64
-                    if (IS_IMM)
-                        goto illegal_insn;
-                    if (!supervisor(dc))
-                        goto priv_insn;
-#endif
-                    save_state(dc);
                     cpu_src1 = gen_load_gpr(dc, rd);
-                    gen_swap_asi(cpu_val, cpu_src1, cpu_addr, insn);
+                    gen_swap_asi(dc, cpu_val, cpu_src1, cpu_addr, insn);
                     break;
 
 #ifndef TARGET_SPARC64
@@ -4806,12 +5238,10 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
                     tcg_gen_qemu_ld64(cpu_val, cpu_addr, dc->mem_idx);
                     break;
                 case 0x18: /* V9 ldswa */
-                    save_state(dc);
-                    gen_ld_asi(cpu_val, cpu_addr, insn, 4, 1);
+                    gen_ld_asi(dc, cpu_val, cpu_addr, insn, MO_TESL);
                     break;
                 case 0x1b: /* V9 ldxa */
-                    save_state(dc);
-                    gen_ld_asi(cpu_val, cpu_addr, insn, 8, 0);
+                    gen_ld_asi(dc, cpu_val, cpu_addr, insn, MO_TEQ);
                     break;
                 case 0x2d: /* V9 prefetch, no effect */
                     goto skip_move;
@@ -4819,17 +5249,15 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
                     if (gen_trap_ifnofpu(dc)) {
                         goto jmp_insn;
                     }
-                    save_state(dc);
-                    gen_ldf_asi(cpu_addr, insn, 4, rd);
-                    gen_update_fprs_dirty(rd);
+                    gen_ldf_asi(dc, cpu_addr, insn, 4, rd);
+                    gen_update_fprs_dirty(dc, rd);
                     goto skip_move;
                 case 0x33: /* V9 lddfa */
                     if (gen_trap_ifnofpu(dc)) {
                         goto jmp_insn;
                     }
-                    save_state(dc);
-                    gen_ldf_asi(cpu_addr, insn, 8, DFPREG(rd));
-                    gen_update_fprs_dirty(DFPREG(rd));
+                    gen_ldf_asi(dc, cpu_addr, insn, 8, DFPREG(rd));
+                    gen_update_fprs_dirty(dc, DFPREG(rd));
                     goto skip_move;
                 case 0x3d: /* V9 prefetcha, no effect */
                     goto skip_move;
@@ -4838,9 +5266,8 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
                     if (gen_trap_ifnofpu(dc)) {
                         goto jmp_insn;
                     }
-                    save_state(dc);
-                    gen_ldf_asi(cpu_addr, insn, 16, QFPREG(rd));
-                    gen_update_fprs_dirty(QFPREG(rd));
+                    gen_ldf_asi(dc, cpu_addr, insn, 16, QFPREG(rd));
+                    gen_update_fprs_dirty(dc, QFPREG(rd));
                     goto skip_move;
 #endif
                 default:
@@ -4856,7 +5283,6 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
                 if (gen_trap_ifnofpu(dc)) {
                     goto jmp_insn;
                 }
-                save_state(dc);
                 switch (xop) {
                 case 0x20:      /* ldf, load fpreg */
                     gen_address_mask(dc, cpu_addr);
@@ -4872,7 +5298,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
                     if (rd == 1) {
                         TCGv_i64 t64 = tcg_temp_new_i64();
                         tcg_gen_qemu_ld64(t64, cpu_addr, dc->mem_idx);
-                        gen_helper_ldxfsr(cpu_env, t64);
+                        gen_helper_ldxfsr(cpu_fsr, cpu_env, cpu_fsr, t64);
                         tcg_temp_free_i64(t64);
                         break;
                     }
@@ -4881,7 +5307,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
                     t0 = get_temp_tl(dc);
                     tcg_gen_qemu_ld32u(t0, cpu_addr, dc->mem_idx);
                     tcg_gen_trunc_tl_i32(cpu_dst_32, t0);
-                    gen_helper_ldfsr(cpu_env, cpu_dst_32);
+                    gen_helper_ldfsr(cpu_fsr, cpu_env, cpu_fsr, cpu_dst_32);
                     break;
                 case 0x22:      /* ldqf, load quad fpreg */
                     {
@@ -4893,7 +5319,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
                         gen_helper_ldqf(cpu_env, cpu_addr, r_const);
                         tcg_temp_free_i32(r_const);
                         gen_op_store_QT0_fpr(QFPREG(rd));
-                        gen_update_fprs_dirty(QFPREG(rd));
+                        gen_update_fprs_dirty(dc, QFPREG(rd));
                     }
                     break;
                 case 0x23:      /* lddf, load double fpreg */
@@ -4926,18 +5352,11 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
                     if (rd & 1)
                         goto illegal_insn;
                     else {
-                        TCGv_i32 r_const;
                         TCGv_i64 t64;
                         TCGv lo;
 
-                        save_state(dc);
                         gen_address_mask(dc, cpu_addr);
-                        r_const = tcg_const_i32(7);
-                        /* XXX remove alignment check */
-                        gen_helper_check_align(cpu_env, cpu_addr, r_const);
-                        tcg_temp_free_i32(r_const);
                         lo = gen_load_gpr(dc, rd + 1);
-
                         t64 = tcg_temp_new_i64();
                         tcg_gen_concat_tl_i64(t64, lo, cpu_val);
                         tcg_gen_qemu_st64(t64, cpu_addr, dc->mem_idx);
@@ -4946,51 +5365,19 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
                     break;
 #if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64)
                 case 0x14: /* sta, V9 stwa, store word alternate */
-#ifndef TARGET_SPARC64
-                    if (IS_IMM)
-                        goto illegal_insn;
-                    if (!supervisor(dc))
-                        goto priv_insn;
-#endif
-                    save_state(dc);
-                    gen_st_asi(cpu_val, cpu_addr, insn, 4);
-                    dc->npc = DYNAMIC_PC;
+                    gen_st_asi(dc, cpu_val, cpu_addr, insn, MO_TEUL);
                     break;
                 case 0x15: /* stba, store byte alternate */
-#ifndef TARGET_SPARC64
-                    if (IS_IMM)
-                        goto illegal_insn;
-                    if (!supervisor(dc))
-                        goto priv_insn;
-#endif
-                    save_state(dc);
-                    gen_st_asi(cpu_val, cpu_addr, insn, 1);
-                    dc->npc = DYNAMIC_PC;
+                    gen_st_asi(dc, cpu_val, cpu_addr, insn, MO_UB);
                     break;
                 case 0x16: /* stha, store halfword alternate */
-#ifndef TARGET_SPARC64
-                    if (IS_IMM)
-                        goto illegal_insn;
-                    if (!supervisor(dc))
-                        goto priv_insn;
-#endif
-                    save_state(dc);
-                    gen_st_asi(cpu_val, cpu_addr, insn, 2);
-                    dc->npc = DYNAMIC_PC;
+                    gen_st_asi(dc, cpu_val, cpu_addr, insn, MO_TEUW);
                     break;
                 case 0x17: /* stda, store double word alternate */
-#ifndef TARGET_SPARC64
-                    if (IS_IMM)
-                        goto illegal_insn;
-                    if (!supervisor(dc))
-                        goto priv_insn;
-#endif
-                    if (rd & 1)
+                    if (rd & 1) {
                         goto illegal_insn;
-                    else {
-                        save_state(dc);
-                        gen_stda_asi(dc, cpu_val, cpu_addr, insn, rd);
                     }
+                    gen_stda_asi(dc, cpu_val, cpu_addr, insn, rd);
                     break;
 #endif
 #ifdef TARGET_SPARC64
@@ -4999,9 +5386,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
                     tcg_gen_qemu_st64(cpu_val, cpu_addr, dc->mem_idx);
                     break;
                 case 0x1e: /* V9 stxa */
-                    save_state(dc);
-                    gen_st_asi(cpu_val, cpu_addr, insn, 8);
-                    dc->npc = DYNAMIC_PC;
+                    gen_st_asi(dc, cpu_val, cpu_addr, insn, MO_TEQ);
                     break;
 #endif
                 default:
@@ -5011,7 +5396,6 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
                 if (gen_trap_ifnofpu(dc)) {
                     goto jmp_insn;
                 }
-                save_state(dc);
                 switch (xop) {
                 case 0x24: /* stf, store fpreg */
                     {
@@ -5024,17 +5408,14 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
                     break;
                 case 0x25: /* stfsr, V9 stxfsr */
                     {
-                        TCGv t = get_temp_tl(dc);
-
-                        tcg_gen_ld_tl(t, cpu_env, offsetof(CPUSPARCState, fsr));
 #ifdef TARGET_SPARC64
                         gen_address_mask(dc, cpu_addr);
                         if (rd == 1) {
-                            tcg_gen_qemu_st64(t, cpu_addr, dc->mem_idx);
+                            tcg_gen_qemu_st64(cpu_fsr, cpu_addr, dc->mem_idx);
                             break;
                         }
 #endif
-                        tcg_gen_qemu_st32(t, cpu_addr, dc->mem_idx);
+                        tcg_gen_qemu_st32(cpu_fsr, cpu_addr, dc->mem_idx);
                     }
                     break;
                 case 0x26:
@@ -5073,34 +5454,29 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
                     goto illegal_insn;
                 }
             } else if (xop > 0x33 && xop < 0x3f) {
-                save_state(dc);
                 switch (xop) {
 #ifdef TARGET_SPARC64
                 case 0x34: /* V9 stfa */
                     if (gen_trap_ifnofpu(dc)) {
                         goto jmp_insn;
                     }
-                    gen_stf_asi(cpu_addr, insn, 4, rd);
+                    gen_stf_asi(dc, cpu_addr, insn, 4, rd);
                     break;
                 case 0x36: /* V9 stqfa */
                     {
-                        TCGv_i32 r_const;
-
                         CHECK_FPU_FEATURE(dc, FLOAT128);
                         if (gen_trap_ifnofpu(dc)) {
                             goto jmp_insn;
                         }
-                        r_const = tcg_const_i32(7);
-                        gen_helper_check_align(cpu_env, cpu_addr, r_const);
-                        tcg_temp_free_i32(r_const);
-                        gen_stf_asi(cpu_addr, insn, 16, QFPREG(rd));
+                        gen_check_align(cpu_addr, 7);
+                        gen_stf_asi(dc, cpu_addr, insn, 16, QFPREG(rd));
                     }
                     break;
                 case 0x37: /* V9 stdfa */
                     if (gen_trap_ifnofpu(dc)) {
                         goto jmp_insn;
                     }
-                    gen_stf_asi(cpu_addr, insn, 8, DFPREG(rd));
+                    gen_stf_asi(dc, cpu_addr, insn, 8, DFPREG(rd));
                     break;
                 case 0x3e: /* V9 casxa */
                     rs2 = GET_FIELD(insn, 27, 31);
@@ -5118,13 +5494,6 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
                 case 0x3c: /* V9 or LEON3 casa */
 #ifndef TARGET_SPARC64
                     CHECK_IU_FEATURE(dc, CASA);
-                    if (IS_IMM) {
-                        goto illegal_insn;
-                    }
-                    /* LEON3 allows CASA from user space with ASI 0xa */
-                    if ((GET_FIELD(insn, 19, 26) != 0xa) && !supervisor(dc)) {
-                        goto priv_insn;
-                    }
 #endif
                     rs2 = GET_FIELD(insn, 27, 31);
                     cpu_src2 = gen_load_gpr(dc, rs2);
@@ -5155,63 +5524,27 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
  jmp_insn:
     goto egress;
  illegal_insn:
-    {
-        TCGv_i32 r_const;
-
-        save_state(dc);
-        r_const = tcg_const_i32(TT_ILL_INSN);
-        gen_helper_raise_exception(cpu_env, r_const);
-        tcg_temp_free_i32(r_const);
-        dc->is_br = 1;
-    }
+    gen_exception(dc, TT_ILL_INSN);
     goto egress;
  unimp_flush:
-    {
-        TCGv_i32 r_const;
-
-        save_state(dc);
-        r_const = tcg_const_i32(TT_UNIMP_FLUSH);
-        gen_helper_raise_exception(cpu_env, r_const);
-        tcg_temp_free_i32(r_const);
-        dc->is_br = 1;
-    }
+    gen_exception(dc, TT_UNIMP_FLUSH);
     goto egress;
 #if !defined(CONFIG_USER_ONLY)
  priv_insn:
-    {
-        TCGv_i32 r_const;
-
-        save_state(dc);
-        r_const = tcg_const_i32(TT_PRIV_INSN);
-        gen_helper_raise_exception(cpu_env, r_const);
-        tcg_temp_free_i32(r_const);
-        dc->is_br = 1;
-    }
+    gen_exception(dc, TT_PRIV_INSN);
     goto egress;
 #endif
  nfpu_insn:
-    save_state(dc);
-    gen_op_fpexception_im(FSR_FTT_UNIMPFPOP);
-    dc->is_br = 1;
+    gen_op_fpexception_im(dc, FSR_FTT_UNIMPFPOP);
     goto egress;
 #if !defined(CONFIG_USER_ONLY) && !defined(TARGET_SPARC64)
  nfq_insn:
-    save_state(dc);
-    gen_op_fpexception_im(FSR_FTT_SEQ_ERROR);
-    dc->is_br = 1;
+    gen_op_fpexception_im(dc, FSR_FTT_SEQ_ERROR);
     goto egress;
 #endif
 #ifndef TARGET_SPARC64
  ncp_insn:
-    {
-        TCGv r_const;
-
-        save_state(dc);
-        r_const = tcg_const_i32(TT_NCP_INSN);
-        gen_helper_raise_exception(cpu_env, r_const);
-        tcg_temp_free(r_const);
-        dc->is_br = 1;
-    }
+    gen_exception(dc, TT_NCP_INSN);
     goto egress;
 #endif
  egress:
@@ -5248,11 +5581,15 @@ void gen_intermediate_code(CPUSPARCState * env, TranslationBlock * tb)
     last_pc = dc->pc;
     dc->npc = (target_ulong) tb->cs_base;
     dc->cc_op = CC_OP_DYNAMIC;
-    dc->mem_idx = cpu_mmu_index(env, false);
+    dc->mem_idx = tb->flags & TB_FLAG_MMU_MASK;
     dc->def = env->def;
     dc->fpu_enabled = tb_fpu_enabled(tb->flags);
     dc->address_mask_32bit = tb_am_enabled(tb->flags);
     dc->singlestep = (cs->singlestep_enabled || singlestep);
+#ifdef TARGET_SPARC64
+    dc->fprs_dirty = 0;
+    dc->asi = (tb->flags >> TB_FLAG_ASI_SHIFT) & 0xff;
+#endif
 
     num_insns = 0;
     max_insns = tb->cflags & CF_COUNT_MASK;
@@ -5362,9 +5699,7 @@ void gen_intermediate_code_init(CPUSPARCState *env)
     static const struct { TCGv_i32 *ptr; int off; const char *name; } r32[] = {
 #ifdef TARGET_SPARC64
         { &cpu_xcc, offsetof(CPUSPARCState, xcc), "xcc" },
-        { &cpu_asi, offsetof(CPUSPARCState, asi), "asi" },
         { &cpu_fprs, offsetof(CPUSPARCState, fprs), "fprs" },
-        { &cpu_softint, offsetof(CPUSPARCState, softint), "softint" },
 #else
         { &cpu_wim, offsetof(CPUSPARCState, wim), "wim" },
 #endif