aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2016-07-14 10:36:27 +0100
committerPeter Maydell <peter.maydell@linaro.org>2016-07-14 10:36:27 +0100
commit5bb2399f9b08198b6c03db10dd46e5a88caa2968 (patch)
tree2a402bbda4e2c6f417f40095ffad7aca80d98c17
parent9ec3025660bcd2f9d308efaf0618453f3696a137 (diff)
parentf9c816c00cf4242542472ae6b2a579b11b7e86f1 (diff)
Merge remote-tracking branch 'remotes/rth/tags/pull-rth-20160712' into staging
target-sparc improvements, v4 # gpg: Signature made Tue 12 Jul 2016 19:04:33 BST # gpg: using RSA key 0xAD1270CC4DD0279B # gpg: Good signature from "Richard Henderson <rth7680@gmail.com>" # gpg: aka "Richard Henderson <rth@redhat.com>" # gpg: aka "Richard Henderson <rth@twiddle.net>" # Primary key fingerprint: 9CB1 8DDA F8E8 49AD 2AFC 16A4 AD12 70CC 4DD0 279B * remotes/rth/tags/pull-rth-20160712: (24 commits) target-sparc: Elide duplicate updates to fprs target-sparc: Use cpu_loop_exit_restore from helper_check_ieee_exceptions target-sparc: Use cpu_fsr in stfsr target-sparc: Use explicit writes to cpu_fsr target-sparc: Remove helper_ldf_asi, helper_stf_asi target-sparc: Directly implement block and short ldf/stf asis target-sparc: Directly implement easy ldf/stf asis target-sparc: Pass TCGMemOp constants to helper_ld/st_asi target-sparc: Fix obvious error in ASI_M_BFILL target-sparc: Directly implement easy ldd/std asis target-sparc: Introduce gen_check_align target-sparc: Use QT0 to return results from ldda target-sparc: Directly implement easy ld/st asis target-sparc: Use defines from asi.h target-sparc: Add UA2005 defines to asi.h target-sparc: Import linux/arch/sparc/include/uapi/asm/asi.h target-sparc: Pass TCGMemOp to gen_ld/st_asi target-sparc: Introduce get_asi target-sparc: Store %asi in TB flags target-sparc: Unify asi handling between 32 and 64-bit ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-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