diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2016-07-14 10:36:27 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2016-07-14 10:36:27 +0100 |
commit | 5bb2399f9b08198b6c03db10dd46e5a88caa2968 (patch) | |
tree | 2a402bbda4e2c6f417f40095ffad7aca80d98c17 | |
parent | 9ec3025660bcd2f9d308efaf0618453f3696a137 (diff) | |
parent | f9c816c00cf4242542472ae6b2a579b11b7e86f1 (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.h | 311 | ||||
-rw-r--r-- | target-sparc/cpu.h | 28 | ||||
-rw-r--r-- | target-sparc/fop_helper.c | 230 | ||||
-rw-r--r-- | target-sparc/helper.h | 168 | ||||
-rw-r--r-- | target-sparc/ldst_helper.c | 696 | ||||
-rw-r--r-- | target-sparc/translate.c | 1273 |
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 |