import Unicorn2
This commit is contained in:
312
qemu/target/sparc/asi.h
Normal file
312
qemu/target/sparc/asi.h
Normal file
@@ -0,0 +1,312 @@
|
||||
#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_HYP_SCRATCHPAD 0x4f /* (4V) Hypervisor scratchpad */
|
||||
#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 */
|
||||
471
qemu/target/sparc/cc_helper.c
Normal file
471
qemu/target/sparc/cc_helper.c
Normal file
@@ -0,0 +1,471 @@
|
||||
/*
|
||||
* Helpers for lazy condition code handling
|
||||
*
|
||||
* Copyright (c) 2003-2005 Fabrice Bellard
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "cpu.h"
|
||||
#include "exec/helper-proto.h"
|
||||
|
||||
static uint32_t compute_all_flags(CPUSPARCState *env)
|
||||
{
|
||||
return env->psr & PSR_ICC;
|
||||
}
|
||||
|
||||
static uint32_t compute_C_flags(CPUSPARCState *env)
|
||||
{
|
||||
return env->psr & PSR_CARRY;
|
||||
}
|
||||
|
||||
static inline uint32_t get_NZ_icc(int32_t dst)
|
||||
{
|
||||
uint32_t ret = 0;
|
||||
|
||||
if (dst == 0) {
|
||||
ret = PSR_ZERO;
|
||||
} else if (dst < 0) {
|
||||
ret = PSR_NEG;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef TARGET_SPARC64
|
||||
static uint32_t compute_all_flags_xcc(CPUSPARCState *env)
|
||||
{
|
||||
return env->xcc & PSR_ICC;
|
||||
}
|
||||
|
||||
static uint32_t compute_C_flags_xcc(CPUSPARCState *env)
|
||||
{
|
||||
return env->xcc & PSR_CARRY;
|
||||
}
|
||||
|
||||
static inline uint32_t get_NZ_xcc(target_long dst)
|
||||
{
|
||||
uint32_t ret = 0;
|
||||
|
||||
if (!dst) {
|
||||
ret = PSR_ZERO;
|
||||
} else if (dst < 0) {
|
||||
ret = PSR_NEG;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline uint32_t get_V_div_icc(target_ulong src2)
|
||||
{
|
||||
uint32_t ret = 0;
|
||||
|
||||
if (src2 != 0) {
|
||||
ret = PSR_OVF;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static uint32_t compute_all_div(CPUSPARCState *env)
|
||||
{
|
||||
uint32_t ret;
|
||||
|
||||
ret = get_NZ_icc(CC_DST);
|
||||
ret |= get_V_div_icc(CC_SRC2);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static uint32_t compute_C_div(CPUSPARCState *env)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline uint32_t get_C_add_icc(uint32_t dst, uint32_t src1)
|
||||
{
|
||||
uint32_t ret = 0;
|
||||
|
||||
if (dst < src1) {
|
||||
ret = PSR_CARRY;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline uint32_t get_C_addx_icc(uint32_t dst, uint32_t src1,
|
||||
uint32_t src2)
|
||||
{
|
||||
uint32_t ret = 0;
|
||||
|
||||
if (((src1 & src2) | (~dst & (src1 | src2))) & (1U << 31)) {
|
||||
ret = PSR_CARRY;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline uint32_t get_V_add_icc(uint32_t dst, uint32_t src1,
|
||||
uint32_t src2)
|
||||
{
|
||||
uint32_t ret = 0;
|
||||
|
||||
if (((src1 ^ src2 ^ -1) & (src1 ^ dst)) & (1U << 31)) {
|
||||
ret = PSR_OVF;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef TARGET_SPARC64
|
||||
static inline uint32_t get_C_add_xcc(target_ulong dst, target_ulong src1)
|
||||
{
|
||||
uint32_t ret = 0;
|
||||
|
||||
if (dst < src1) {
|
||||
ret = PSR_CARRY;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline uint32_t get_C_addx_xcc(target_ulong dst, target_ulong src1,
|
||||
target_ulong src2)
|
||||
{
|
||||
uint32_t ret = 0;
|
||||
|
||||
if (((src1 & src2) | (~dst & (src1 | src2))) & (1ULL << 63)) {
|
||||
ret = PSR_CARRY;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline uint32_t get_V_add_xcc(target_ulong dst, target_ulong src1,
|
||||
target_ulong src2)
|
||||
{
|
||||
uint32_t ret = 0;
|
||||
|
||||
if (((src1 ^ src2 ^ -1) & (src1 ^ dst)) & (1ULL << 63)) {
|
||||
ret = PSR_OVF;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static uint32_t compute_all_add_xcc(CPUSPARCState *env)
|
||||
{
|
||||
uint32_t ret;
|
||||
|
||||
ret = get_NZ_xcc(CC_DST);
|
||||
ret |= get_C_add_xcc(CC_DST, CC_SRC);
|
||||
ret |= get_V_add_xcc(CC_DST, CC_SRC, CC_SRC2);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static uint32_t compute_C_add_xcc(CPUSPARCState *env)
|
||||
{
|
||||
return get_C_add_xcc(CC_DST, CC_SRC);
|
||||
}
|
||||
#endif
|
||||
|
||||
static uint32_t compute_all_add(CPUSPARCState *env)
|
||||
{
|
||||
uint32_t ret;
|
||||
|
||||
ret = get_NZ_icc(CC_DST);
|
||||
ret |= get_C_add_icc(CC_DST, CC_SRC);
|
||||
ret |= get_V_add_icc(CC_DST, CC_SRC, CC_SRC2);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static uint32_t compute_C_add(CPUSPARCState *env)
|
||||
{
|
||||
return get_C_add_icc(CC_DST, CC_SRC);
|
||||
}
|
||||
|
||||
#ifdef TARGET_SPARC64
|
||||
static uint32_t compute_all_addx_xcc(CPUSPARCState *env)
|
||||
{
|
||||
uint32_t ret;
|
||||
|
||||
ret = get_NZ_xcc(CC_DST);
|
||||
ret |= get_C_addx_xcc(CC_DST, CC_SRC, CC_SRC2);
|
||||
ret |= get_V_add_xcc(CC_DST, CC_SRC, CC_SRC2);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static uint32_t compute_C_addx_xcc(CPUSPARCState *env)
|
||||
{
|
||||
return get_C_addx_xcc(CC_DST, CC_SRC, CC_SRC2);
|
||||
}
|
||||
#endif
|
||||
|
||||
static uint32_t compute_all_addx(CPUSPARCState *env)
|
||||
{
|
||||
uint32_t ret;
|
||||
|
||||
ret = get_NZ_icc(CC_DST);
|
||||
ret |= get_C_addx_icc(CC_DST, CC_SRC, CC_SRC2);
|
||||
ret |= get_V_add_icc(CC_DST, CC_SRC, CC_SRC2);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static uint32_t compute_C_addx(CPUSPARCState *env)
|
||||
{
|
||||
return get_C_addx_icc(CC_DST, CC_SRC, CC_SRC2);
|
||||
}
|
||||
|
||||
static inline uint32_t get_V_tag_icc(target_ulong src1, target_ulong src2)
|
||||
{
|
||||
uint32_t ret = 0;
|
||||
|
||||
if ((src1 | src2) & 0x3) {
|
||||
ret = PSR_OVF;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static uint32_t compute_all_tadd(CPUSPARCState *env)
|
||||
{
|
||||
uint32_t ret;
|
||||
|
||||
ret = get_NZ_icc(CC_DST);
|
||||
ret |= get_C_add_icc(CC_DST, CC_SRC);
|
||||
ret |= get_V_add_icc(CC_DST, CC_SRC, CC_SRC2);
|
||||
ret |= get_V_tag_icc(CC_SRC, CC_SRC2);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static uint32_t compute_all_taddtv(CPUSPARCState *env)
|
||||
{
|
||||
uint32_t ret;
|
||||
|
||||
ret = get_NZ_icc(CC_DST);
|
||||
ret |= get_C_add_icc(CC_DST, CC_SRC);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline uint32_t get_C_sub_icc(uint32_t src1, uint32_t src2)
|
||||
{
|
||||
uint32_t ret = 0;
|
||||
|
||||
if (src1 < src2) {
|
||||
ret = PSR_CARRY;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline uint32_t get_C_subx_icc(uint32_t dst, uint32_t src1,
|
||||
uint32_t src2)
|
||||
{
|
||||
uint32_t ret = 0;
|
||||
|
||||
if (((~src1 & src2) | (dst & (~src1 | src2))) & (1U << 31)) {
|
||||
ret = PSR_CARRY;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline uint32_t get_V_sub_icc(uint32_t dst, uint32_t src1,
|
||||
uint32_t src2)
|
||||
{
|
||||
uint32_t ret = 0;
|
||||
|
||||
if (((src1 ^ src2) & (src1 ^ dst)) & (1U << 31)) {
|
||||
ret = PSR_OVF;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
#ifdef TARGET_SPARC64
|
||||
static inline uint32_t get_C_sub_xcc(target_ulong src1, target_ulong src2)
|
||||
{
|
||||
uint32_t ret = 0;
|
||||
|
||||
if (src1 < src2) {
|
||||
ret = PSR_CARRY;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline uint32_t get_C_subx_xcc(target_ulong dst, target_ulong src1,
|
||||
target_ulong src2)
|
||||
{
|
||||
uint32_t ret = 0;
|
||||
|
||||
if (((~src1 & src2) | (dst & (~src1 | src2))) & (1ULL << 63)) {
|
||||
ret = PSR_CARRY;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline uint32_t get_V_sub_xcc(target_ulong dst, target_ulong src1,
|
||||
target_ulong src2)
|
||||
{
|
||||
uint32_t ret = 0;
|
||||
|
||||
if (((src1 ^ src2) & (src1 ^ dst)) & (1ULL << 63)) {
|
||||
ret = PSR_OVF;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static uint32_t compute_all_sub_xcc(CPUSPARCState *env)
|
||||
{
|
||||
uint32_t ret;
|
||||
|
||||
ret = get_NZ_xcc(CC_DST);
|
||||
ret |= get_C_sub_xcc(CC_SRC, CC_SRC2);
|
||||
ret |= get_V_sub_xcc(CC_DST, CC_SRC, CC_SRC2);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static uint32_t compute_C_sub_xcc(CPUSPARCState *env)
|
||||
{
|
||||
return get_C_sub_xcc(CC_SRC, CC_SRC2);
|
||||
}
|
||||
#endif
|
||||
|
||||
static uint32_t compute_all_sub(CPUSPARCState *env)
|
||||
{
|
||||
uint32_t ret;
|
||||
|
||||
ret = get_NZ_icc(CC_DST);
|
||||
ret |= get_C_sub_icc(CC_SRC, CC_SRC2);
|
||||
ret |= get_V_sub_icc(CC_DST, CC_SRC, CC_SRC2);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static uint32_t compute_C_sub(CPUSPARCState *env)
|
||||
{
|
||||
return get_C_sub_icc(CC_SRC, CC_SRC2);
|
||||
}
|
||||
|
||||
#ifdef TARGET_SPARC64
|
||||
static uint32_t compute_all_subx_xcc(CPUSPARCState *env)
|
||||
{
|
||||
uint32_t ret;
|
||||
|
||||
ret = get_NZ_xcc(CC_DST);
|
||||
ret |= get_C_subx_xcc(CC_DST, CC_SRC, CC_SRC2);
|
||||
ret |= get_V_sub_xcc(CC_DST, CC_SRC, CC_SRC2);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static uint32_t compute_C_subx_xcc(CPUSPARCState *env)
|
||||
{
|
||||
return get_C_subx_xcc(CC_DST, CC_SRC, CC_SRC2);
|
||||
}
|
||||
#endif
|
||||
|
||||
static uint32_t compute_all_subx(CPUSPARCState *env)
|
||||
{
|
||||
uint32_t ret;
|
||||
|
||||
ret = get_NZ_icc(CC_DST);
|
||||
ret |= get_C_subx_icc(CC_DST, CC_SRC, CC_SRC2);
|
||||
ret |= get_V_sub_icc(CC_DST, CC_SRC, CC_SRC2);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static uint32_t compute_C_subx(CPUSPARCState *env)
|
||||
{
|
||||
return get_C_subx_icc(CC_DST, CC_SRC, CC_SRC2);
|
||||
}
|
||||
|
||||
static uint32_t compute_all_tsub(CPUSPARCState *env)
|
||||
{
|
||||
uint32_t ret;
|
||||
|
||||
ret = get_NZ_icc(CC_DST);
|
||||
ret |= get_C_sub_icc(CC_SRC, CC_SRC2);
|
||||
ret |= get_V_sub_icc(CC_DST, CC_SRC, CC_SRC2);
|
||||
ret |= get_V_tag_icc(CC_SRC, CC_SRC2);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static uint32_t compute_all_tsubtv(CPUSPARCState *env)
|
||||
{
|
||||
uint32_t ret;
|
||||
|
||||
ret = get_NZ_icc(CC_DST);
|
||||
ret |= get_C_sub_icc(CC_SRC, CC_SRC2);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static uint32_t compute_all_logic(CPUSPARCState *env)
|
||||
{
|
||||
return get_NZ_icc(CC_DST);
|
||||
}
|
||||
|
||||
static uint32_t compute_C_logic(CPUSPARCState *env)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef TARGET_SPARC64
|
||||
static uint32_t compute_all_logic_xcc(CPUSPARCState *env)
|
||||
{
|
||||
return get_NZ_xcc(CC_DST);
|
||||
}
|
||||
#endif
|
||||
|
||||
typedef struct CCTable {
|
||||
uint32_t (*compute_all)(CPUSPARCState *env); /* return all the flags */
|
||||
uint32_t (*compute_c)(CPUSPARCState *env); /* return the C flag */
|
||||
} CCTable;
|
||||
|
||||
static const CCTable icc_table[CC_OP_NB] = {
|
||||
/* CC_OP_DYNAMIC should never happen */
|
||||
[CC_OP_FLAGS] = { compute_all_flags, compute_C_flags },
|
||||
[CC_OP_DIV] = { compute_all_div, compute_C_div },
|
||||
[CC_OP_ADD] = { compute_all_add, compute_C_add },
|
||||
[CC_OP_ADDX] = { compute_all_addx, compute_C_addx },
|
||||
[CC_OP_TADD] = { compute_all_tadd, compute_C_add },
|
||||
[CC_OP_TADDTV] = { compute_all_taddtv, compute_C_add },
|
||||
[CC_OP_SUB] = { compute_all_sub, compute_C_sub },
|
||||
[CC_OP_SUBX] = { compute_all_subx, compute_C_subx },
|
||||
[CC_OP_TSUB] = { compute_all_tsub, compute_C_sub },
|
||||
[CC_OP_TSUBTV] = { compute_all_tsubtv, compute_C_sub },
|
||||
[CC_OP_LOGIC] = { compute_all_logic, compute_C_logic },
|
||||
};
|
||||
|
||||
#ifdef TARGET_SPARC64
|
||||
static const CCTable xcc_table[CC_OP_NB] = {
|
||||
/* CC_OP_DYNAMIC should never happen */
|
||||
[CC_OP_FLAGS] = { compute_all_flags_xcc, compute_C_flags_xcc },
|
||||
[CC_OP_DIV] = { compute_all_logic_xcc, compute_C_logic },
|
||||
[CC_OP_ADD] = { compute_all_add_xcc, compute_C_add_xcc },
|
||||
[CC_OP_ADDX] = { compute_all_addx_xcc, compute_C_addx_xcc },
|
||||
[CC_OP_TADD] = { compute_all_add_xcc, compute_C_add_xcc },
|
||||
[CC_OP_TADDTV] = { compute_all_add_xcc, compute_C_add_xcc },
|
||||
[CC_OP_SUB] = { compute_all_sub_xcc, compute_C_sub_xcc },
|
||||
[CC_OP_SUBX] = { compute_all_subx_xcc, compute_C_subx_xcc },
|
||||
[CC_OP_TSUB] = { compute_all_sub_xcc, compute_C_sub_xcc },
|
||||
[CC_OP_TSUBTV] = { compute_all_sub_xcc, compute_C_sub_xcc },
|
||||
[CC_OP_LOGIC] = { compute_all_logic_xcc, compute_C_logic },
|
||||
};
|
||||
#endif
|
||||
|
||||
void helper_compute_psr(CPUSPARCState *env)
|
||||
{
|
||||
uint32_t new_psr;
|
||||
|
||||
new_psr = icc_table[CC_OP].compute_all(env);
|
||||
env->psr = new_psr;
|
||||
#ifdef TARGET_SPARC64
|
||||
new_psr = xcc_table[CC_OP].compute_all(env);
|
||||
env->xcc = new_psr;
|
||||
#endif
|
||||
CC_OP = CC_OP_FLAGS;
|
||||
}
|
||||
|
||||
uint32_t helper_compute_C_icc(CPUSPARCState *env)
|
||||
{
|
||||
return icc_table[CC_OP].compute_c(env) >> PSR_CARRY_SHIFT;
|
||||
}
|
||||
28
qemu/target/sparc/cpu-param.h
Normal file
28
qemu/target/sparc/cpu-param.h
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Sparc cpu parameters for qemu.
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.0+
|
||||
*/
|
||||
|
||||
#ifndef SPARC_CPU_PARAM_H
|
||||
#define SPARC_CPU_PARAM_H 1
|
||||
|
||||
#ifdef TARGET_SPARC64
|
||||
# define TARGET_LONG_BITS 64
|
||||
# define TARGET_PAGE_BITS 13 /* 8k */
|
||||
# define TARGET_PHYS_ADDR_SPACE_BITS 41
|
||||
# ifdef TARGET_ABI32
|
||||
# define TARGET_VIRT_ADDR_SPACE_BITS 32
|
||||
# else
|
||||
# define TARGET_VIRT_ADDR_SPACE_BITS 44
|
||||
# endif
|
||||
# define NB_MMU_MODES 6
|
||||
#else
|
||||
# define TARGET_LONG_BITS 32
|
||||
# define TARGET_PAGE_BITS 12 /* 4k */
|
||||
# define TARGET_PHYS_ADDR_SPACE_BITS 36
|
||||
# define TARGET_VIRT_ADDR_SPACE_BITS 32
|
||||
# define NB_MMU_MODES 3
|
||||
#endif
|
||||
|
||||
#endif
|
||||
48
qemu/target/sparc/cpu-qom.h
Normal file
48
qemu/target/sparc/cpu-qom.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* QEMU SPARC CPU
|
||||
*
|
||||
* Copyright (c) 2012 SUSE LINUX Products GmbH
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see
|
||||
* <http://www.gnu.org/licenses/lgpl-2.1.html>
|
||||
*/
|
||||
#ifndef QEMU_SPARC_CPU_QOM_H
|
||||
#define QEMU_SPARC_CPU_QOM_H
|
||||
|
||||
#include "hw/core/cpu.h"
|
||||
|
||||
#define SPARC_CPU(obj) ((SPARCCPU *)obj)
|
||||
#define SPARC_CPU_CLASS(klass) ((SPARCCPUClass *)klass)
|
||||
#define SPARC_CPU_GET_CLASS(obj) (&((SPARCCPU *)obj)->cc)
|
||||
|
||||
typedef struct sparc_def_t sparc_def_t;
|
||||
/**
|
||||
* SPARCCPUClass:
|
||||
* @parent_realize: The parent class' realize handler.
|
||||
* @parent_reset: The parent class' reset handler.
|
||||
*
|
||||
* A SPARC CPU model.
|
||||
*/
|
||||
typedef struct SPARCCPUClass {
|
||||
/*< private >*/
|
||||
CPUClass parent_class;
|
||||
/*< public >*/
|
||||
|
||||
void (*parent_reset)(CPUState *cpu);
|
||||
const sparc_def_t *cpu_def;
|
||||
} SPARCCPUClass;
|
||||
|
||||
typedef struct SPARCCPU SPARCCPU;
|
||||
|
||||
#endif
|
||||
571
qemu/target/sparc/cpu.c
Normal file
571
qemu/target/sparc/cpu.c
Normal file
@@ -0,0 +1,571 @@
|
||||
/*
|
||||
* Sparc CPU init helpers
|
||||
*
|
||||
* Copyright (c) 2003-2005 Fabrice Bellard
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "cpu.h"
|
||||
#include "exec/exec-all.h"
|
||||
|
||||
static void sparc_cpu_reset(CPUState *dev)
|
||||
{
|
||||
CPUState *s = CPU(dev);
|
||||
SPARCCPU *cpu = SPARC_CPU(s);
|
||||
SPARCCPUClass *scc = SPARC_CPU_GET_CLASS(cpu);
|
||||
CPUSPARCState *env = &cpu->env;
|
||||
|
||||
scc->parent_reset(dev);
|
||||
|
||||
memset(env, 0, offsetof(CPUSPARCState, end_reset_fields));
|
||||
env->cwp = 0;
|
||||
#ifndef TARGET_SPARC64
|
||||
env->wim = 1;
|
||||
#endif
|
||||
env->regwptr = env->regbase + (env->cwp * 16);
|
||||
CC_OP = CC_OP_FLAGS;
|
||||
#if !defined(TARGET_SPARC64)
|
||||
env->psret = 0;
|
||||
env->psrs = 1;
|
||||
env->psrps = 1;
|
||||
#endif
|
||||
#ifdef TARGET_SPARC64
|
||||
env->pstate = PS_PRIV | PS_RED | PS_PEF;
|
||||
if (!cpu_has_hypervisor(env)) {
|
||||
env->pstate |= PS_AG;
|
||||
}
|
||||
env->hpstate = cpu_has_hypervisor(env) ? HS_PRIV : 0;
|
||||
env->tl = env->maxtl;
|
||||
env->gl = 2;
|
||||
cpu_tsptr(env)->tt = TT_POWER_ON_RESET;
|
||||
env->lsu = 0;
|
||||
#else
|
||||
env->mmuregs[0] &= ~(MMU_E | MMU_NF);
|
||||
env->mmuregs[0] |= env->def.mmu_bm;
|
||||
#endif
|
||||
env->pc = 0;
|
||||
env->npc = env->pc + 4;
|
||||
env->cache_control = 0;
|
||||
}
|
||||
|
||||
static bool sparc_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
|
||||
{
|
||||
if (interrupt_request & CPU_INTERRUPT_HARD) {
|
||||
SPARCCPU *cpu = SPARC_CPU(cs);
|
||||
CPUSPARCState *env = &cpu->env;
|
||||
|
||||
if (cpu_interrupts_enabled(env) && env->interrupt_index > 0) {
|
||||
int pil = env->interrupt_index & 0xf;
|
||||
int type = env->interrupt_index & 0xf0;
|
||||
|
||||
if (type != TT_EXTINT || cpu_pil_allowed(env, pil)) {
|
||||
cs->exception_index = env->interrupt_index;
|
||||
sparc_cpu_do_interrupt(cs);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void cpu_sparc_set_id(CPUSPARCState *env, unsigned int cpu)
|
||||
{
|
||||
#if !defined(TARGET_SPARC64)
|
||||
env->mxccregs[7] = ((cpu + 8) & 0xf) << 24;
|
||||
#endif
|
||||
}
|
||||
|
||||
static const sparc_def_t sparc_defs[] = {
|
||||
#ifdef TARGET_SPARC64
|
||||
{
|
||||
.name = "Fujitsu Sparc64",
|
||||
.iu_version = ((0x04ULL << 48) | (0x02ULL << 32) | (0ULL << 24)),
|
||||
.fpu_version = 0x00000000,
|
||||
.mmu_version = mmu_us_12,
|
||||
.nwindows = 4,
|
||||
.maxtl = 4,
|
||||
.features = CPU_DEFAULT_FEATURES,
|
||||
},
|
||||
{
|
||||
.name = "Fujitsu Sparc64 III",
|
||||
.iu_version = ((0x04ULL << 48) | (0x03ULL << 32) | (0ULL << 24)),
|
||||
.fpu_version = 0x00000000,
|
||||
.mmu_version = mmu_us_12,
|
||||
.nwindows = 5,
|
||||
.maxtl = 4,
|
||||
.features = CPU_DEFAULT_FEATURES,
|
||||
},
|
||||
{
|
||||
.name = "Fujitsu Sparc64 IV",
|
||||
.iu_version = ((0x04ULL << 48) | (0x04ULL << 32) | (0ULL << 24)),
|
||||
.fpu_version = 0x00000000,
|
||||
.mmu_version = mmu_us_12,
|
||||
.nwindows = 8,
|
||||
.maxtl = 5,
|
||||
.features = CPU_DEFAULT_FEATURES,
|
||||
},
|
||||
{
|
||||
.name = "Fujitsu Sparc64 V",
|
||||
.iu_version = ((0x04ULL << 48) | (0x05ULL << 32) | (0x51ULL << 24)),
|
||||
.fpu_version = 0x00000000,
|
||||
.mmu_version = mmu_us_12,
|
||||
.nwindows = 8,
|
||||
.maxtl = 5,
|
||||
.features = CPU_DEFAULT_FEATURES,
|
||||
},
|
||||
{
|
||||
.name = "TI UltraSparc I",
|
||||
.iu_version = ((0x17ULL << 48) | (0x10ULL << 32) | (0x40ULL << 24)),
|
||||
.fpu_version = 0x00000000,
|
||||
.mmu_version = mmu_us_12,
|
||||
.nwindows = 8,
|
||||
.maxtl = 5,
|
||||
.features = CPU_DEFAULT_FEATURES,
|
||||
},
|
||||
{
|
||||
.name = "TI UltraSparc II",
|
||||
.iu_version = ((0x17ULL << 48) | (0x11ULL << 32) | (0x20ULL << 24)),
|
||||
.fpu_version = 0x00000000,
|
||||
.mmu_version = mmu_us_12,
|
||||
.nwindows = 8,
|
||||
.maxtl = 5,
|
||||
.features = CPU_DEFAULT_FEATURES,
|
||||
},
|
||||
{
|
||||
.name = "TI UltraSparc IIi",
|
||||
.iu_version = ((0x17ULL << 48) | (0x12ULL << 32) | (0x91ULL << 24)),
|
||||
.fpu_version = 0x00000000,
|
||||
.mmu_version = mmu_us_12,
|
||||
.nwindows = 8,
|
||||
.maxtl = 5,
|
||||
.features = CPU_DEFAULT_FEATURES,
|
||||
},
|
||||
{
|
||||
.name = "TI UltraSparc IIe",
|
||||
.iu_version = ((0x17ULL << 48) | (0x13ULL << 32) | (0x14ULL << 24)),
|
||||
.fpu_version = 0x00000000,
|
||||
.mmu_version = mmu_us_12,
|
||||
.nwindows = 8,
|
||||
.maxtl = 5,
|
||||
.features = CPU_DEFAULT_FEATURES,
|
||||
},
|
||||
{
|
||||
.name = "Sun UltraSparc III",
|
||||
.iu_version = ((0x3eULL << 48) | (0x14ULL << 32) | (0x34ULL << 24)),
|
||||
.fpu_version = 0x00000000,
|
||||
.mmu_version = mmu_us_12,
|
||||
.nwindows = 8,
|
||||
.maxtl = 5,
|
||||
.features = CPU_DEFAULT_FEATURES,
|
||||
},
|
||||
{
|
||||
.name = "Sun UltraSparc III Cu",
|
||||
.iu_version = ((0x3eULL << 48) | (0x15ULL << 32) | (0x41ULL << 24)),
|
||||
.fpu_version = 0x00000000,
|
||||
.mmu_version = mmu_us_3,
|
||||
.nwindows = 8,
|
||||
.maxtl = 5,
|
||||
.features = CPU_DEFAULT_FEATURES,
|
||||
},
|
||||
{
|
||||
.name = "Sun UltraSparc IIIi",
|
||||
.iu_version = ((0x3eULL << 48) | (0x16ULL << 32) | (0x34ULL << 24)),
|
||||
.fpu_version = 0x00000000,
|
||||
.mmu_version = mmu_us_12,
|
||||
.nwindows = 8,
|
||||
.maxtl = 5,
|
||||
.features = CPU_DEFAULT_FEATURES,
|
||||
},
|
||||
{
|
||||
.name = "Sun UltraSparc IV",
|
||||
.iu_version = ((0x3eULL << 48) | (0x18ULL << 32) | (0x31ULL << 24)),
|
||||
.fpu_version = 0x00000000,
|
||||
.mmu_version = mmu_us_4,
|
||||
.nwindows = 8,
|
||||
.maxtl = 5,
|
||||
.features = CPU_DEFAULT_FEATURES,
|
||||
},
|
||||
{
|
||||
.name = "Sun UltraSparc IV+",
|
||||
.iu_version = ((0x3eULL << 48) | (0x19ULL << 32) | (0x22ULL << 24)),
|
||||
.fpu_version = 0x00000000,
|
||||
.mmu_version = mmu_us_12,
|
||||
.nwindows = 8,
|
||||
.maxtl = 5,
|
||||
.features = CPU_DEFAULT_FEATURES | CPU_FEATURE_CMT,
|
||||
},
|
||||
{
|
||||
.name = "Sun UltraSparc IIIi+",
|
||||
.iu_version = ((0x3eULL << 48) | (0x22ULL << 32) | (0ULL << 24)),
|
||||
.fpu_version = 0x00000000,
|
||||
.mmu_version = mmu_us_3,
|
||||
.nwindows = 8,
|
||||
.maxtl = 5,
|
||||
.features = CPU_DEFAULT_FEATURES,
|
||||
},
|
||||
{
|
||||
.name = "Sun UltraSparc T1",
|
||||
/* defined in sparc_ifu_fdp.v and ctu.h */
|
||||
.iu_version = ((0x3eULL << 48) | (0x23ULL << 32) | (0x02ULL << 24)),
|
||||
.fpu_version = 0x00000000,
|
||||
.mmu_version = mmu_sun4v,
|
||||
.nwindows = 8,
|
||||
.maxtl = 6,
|
||||
.features = CPU_DEFAULT_FEATURES | CPU_FEATURE_HYPV | CPU_FEATURE_CMT
|
||||
| CPU_FEATURE_GL,
|
||||
},
|
||||
{
|
||||
.name = "Sun UltraSparc T2",
|
||||
/* defined in tlu_asi_ctl.v and n2_revid_cust.v */
|
||||
.iu_version = ((0x3eULL << 48) | (0x24ULL << 32) | (0x02ULL << 24)),
|
||||
.fpu_version = 0x00000000,
|
||||
.mmu_version = mmu_sun4v,
|
||||
.nwindows = 8,
|
||||
.maxtl = 6,
|
||||
.features = CPU_DEFAULT_FEATURES | CPU_FEATURE_HYPV | CPU_FEATURE_CMT
|
||||
| CPU_FEATURE_GL,
|
||||
},
|
||||
{
|
||||
.name = "NEC UltraSparc I",
|
||||
.iu_version = ((0x22ULL << 48) | (0x10ULL << 32) | (0x40ULL << 24)),
|
||||
.fpu_version = 0x00000000,
|
||||
.mmu_version = mmu_us_12,
|
||||
.nwindows = 8,
|
||||
.maxtl = 5,
|
||||
.features = CPU_DEFAULT_FEATURES,
|
||||
},
|
||||
#else
|
||||
{
|
||||
.name = "Fujitsu MB86904",
|
||||
.iu_version = 0x04 << 24, /* Impl 0, ver 4 */
|
||||
.fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
|
||||
.mmu_version = 0x04 << 24, /* Impl 0, ver 4 */
|
||||
.mmu_bm = 0x00004000,
|
||||
.mmu_ctpr_mask = 0x00ffffc0,
|
||||
.mmu_cxr_mask = 0x000000ff,
|
||||
.mmu_sfsr_mask = 0x00016fff,
|
||||
.mmu_trcr_mask = 0x00ffffff,
|
||||
.nwindows = 8,
|
||||
.features = CPU_DEFAULT_FEATURES,
|
||||
},
|
||||
{
|
||||
.name = "Fujitsu MB86907",
|
||||
.iu_version = 0x05 << 24, /* Impl 0, ver 5 */
|
||||
.fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
|
||||
.mmu_version = 0x05 << 24, /* Impl 0, ver 5 */
|
||||
.mmu_bm = 0x00004000,
|
||||
.mmu_ctpr_mask = 0xffffffc0,
|
||||
.mmu_cxr_mask = 0x000000ff,
|
||||
.mmu_sfsr_mask = 0x00016fff,
|
||||
.mmu_trcr_mask = 0xffffffff,
|
||||
.nwindows = 8,
|
||||
.features = CPU_DEFAULT_FEATURES,
|
||||
},
|
||||
{
|
||||
.name = "TI MicroSparc I",
|
||||
.iu_version = 0x41000000,
|
||||
.fpu_version = 4 << 17,
|
||||
.mmu_version = 0x41000000,
|
||||
.mmu_bm = 0x00004000,
|
||||
.mmu_ctpr_mask = 0x007ffff0,
|
||||
.mmu_cxr_mask = 0x0000003f,
|
||||
.mmu_sfsr_mask = 0x00016fff,
|
||||
.mmu_trcr_mask = 0x0000003f,
|
||||
.nwindows = 7,
|
||||
.features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_MUL |
|
||||
CPU_FEATURE_DIV | CPU_FEATURE_FLUSH | CPU_FEATURE_FSQRT |
|
||||
CPU_FEATURE_FMUL,
|
||||
},
|
||||
{
|
||||
.name = "TI MicroSparc II",
|
||||
.iu_version = 0x42000000,
|
||||
.fpu_version = 4 << 17,
|
||||
.mmu_version = 0x02000000,
|
||||
.mmu_bm = 0x00004000,
|
||||
.mmu_ctpr_mask = 0x00ffffc0,
|
||||
.mmu_cxr_mask = 0x000000ff,
|
||||
.mmu_sfsr_mask = 0x00016fff,
|
||||
.mmu_trcr_mask = 0x00ffffff,
|
||||
.nwindows = 8,
|
||||
.features = CPU_DEFAULT_FEATURES,
|
||||
},
|
||||
{
|
||||
.name = "TI MicroSparc IIep",
|
||||
.iu_version = 0x42000000,
|
||||
.fpu_version = 4 << 17,
|
||||
.mmu_version = 0x04000000,
|
||||
.mmu_bm = 0x00004000,
|
||||
.mmu_ctpr_mask = 0x00ffffc0,
|
||||
.mmu_cxr_mask = 0x000000ff,
|
||||
.mmu_sfsr_mask = 0x00016bff,
|
||||
.mmu_trcr_mask = 0x00ffffff,
|
||||
.nwindows = 8,
|
||||
.features = CPU_DEFAULT_FEATURES,
|
||||
},
|
||||
{
|
||||
.name = "TI SuperSparc 40", /* STP1020NPGA */
|
||||
.iu_version = 0x41000000, /* SuperSPARC 2.x */
|
||||
.fpu_version = 0 << 17,
|
||||
.mmu_version = 0x00000800, /* SuperSPARC 2.x, no MXCC */
|
||||
.mmu_bm = 0x00002000,
|
||||
.mmu_ctpr_mask = 0xffffffc0,
|
||||
.mmu_cxr_mask = 0x0000ffff,
|
||||
.mmu_sfsr_mask = 0xffffffff,
|
||||
.mmu_trcr_mask = 0xffffffff,
|
||||
.nwindows = 8,
|
||||
.features = CPU_DEFAULT_FEATURES,
|
||||
},
|
||||
{
|
||||
.name = "TI SuperSparc 50", /* STP1020PGA */
|
||||
.iu_version = 0x40000000, /* SuperSPARC 3.x */
|
||||
.fpu_version = 0 << 17,
|
||||
.mmu_version = 0x01000800, /* SuperSPARC 3.x, no MXCC */
|
||||
.mmu_bm = 0x00002000,
|
||||
.mmu_ctpr_mask = 0xffffffc0,
|
||||
.mmu_cxr_mask = 0x0000ffff,
|
||||
.mmu_sfsr_mask = 0xffffffff,
|
||||
.mmu_trcr_mask = 0xffffffff,
|
||||
.nwindows = 8,
|
||||
.features = CPU_DEFAULT_FEATURES,
|
||||
},
|
||||
{
|
||||
.name = "TI SuperSparc 51",
|
||||
.iu_version = 0x40000000, /* SuperSPARC 3.x */
|
||||
.fpu_version = 0 << 17,
|
||||
.mmu_version = 0x01000000, /* SuperSPARC 3.x, MXCC */
|
||||
.mmu_bm = 0x00002000,
|
||||
.mmu_ctpr_mask = 0xffffffc0,
|
||||
.mmu_cxr_mask = 0x0000ffff,
|
||||
.mmu_sfsr_mask = 0xffffffff,
|
||||
.mmu_trcr_mask = 0xffffffff,
|
||||
.mxcc_version = 0x00000104,
|
||||
.nwindows = 8,
|
||||
.features = CPU_DEFAULT_FEATURES,
|
||||
},
|
||||
{
|
||||
.name = "TI SuperSparc 60", /* STP1020APGA */
|
||||
.iu_version = 0x40000000, /* SuperSPARC 3.x */
|
||||
.fpu_version = 0 << 17,
|
||||
.mmu_version = 0x01000800, /* SuperSPARC 3.x, no MXCC */
|
||||
.mmu_bm = 0x00002000,
|
||||
.mmu_ctpr_mask = 0xffffffc0,
|
||||
.mmu_cxr_mask = 0x0000ffff,
|
||||
.mmu_sfsr_mask = 0xffffffff,
|
||||
.mmu_trcr_mask = 0xffffffff,
|
||||
.nwindows = 8,
|
||||
.features = CPU_DEFAULT_FEATURES,
|
||||
},
|
||||
{
|
||||
.name = "TI SuperSparc 61",
|
||||
.iu_version = 0x44000000, /* SuperSPARC 3.x */
|
||||
.fpu_version = 0 << 17,
|
||||
.mmu_version = 0x01000000, /* SuperSPARC 3.x, MXCC */
|
||||
.mmu_bm = 0x00002000,
|
||||
.mmu_ctpr_mask = 0xffffffc0,
|
||||
.mmu_cxr_mask = 0x0000ffff,
|
||||
.mmu_sfsr_mask = 0xffffffff,
|
||||
.mmu_trcr_mask = 0xffffffff,
|
||||
.mxcc_version = 0x00000104,
|
||||
.nwindows = 8,
|
||||
.features = CPU_DEFAULT_FEATURES,
|
||||
},
|
||||
{
|
||||
.name = "TI SuperSparc II",
|
||||
.iu_version = 0x40000000, /* SuperSPARC II 1.x */
|
||||
.fpu_version = 0 << 17,
|
||||
.mmu_version = 0x08000000, /* SuperSPARC II 1.x, MXCC */
|
||||
.mmu_bm = 0x00002000,
|
||||
.mmu_ctpr_mask = 0xffffffc0,
|
||||
.mmu_cxr_mask = 0x0000ffff,
|
||||
.mmu_sfsr_mask = 0xffffffff,
|
||||
.mmu_trcr_mask = 0xffffffff,
|
||||
.mxcc_version = 0x00000104,
|
||||
.nwindows = 8,
|
||||
.features = CPU_DEFAULT_FEATURES,
|
||||
},
|
||||
{
|
||||
.name = "LEON2",
|
||||
.iu_version = 0xf2000000,
|
||||
.fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
|
||||
.mmu_version = 0xf2000000,
|
||||
.mmu_bm = 0x00004000,
|
||||
.mmu_ctpr_mask = 0x007ffff0,
|
||||
.mmu_cxr_mask = 0x0000003f,
|
||||
.mmu_sfsr_mask = 0xffffffff,
|
||||
.mmu_trcr_mask = 0xffffffff,
|
||||
.nwindows = 8,
|
||||
.features = CPU_DEFAULT_FEATURES | CPU_FEATURE_TA0_SHUTDOWN,
|
||||
},
|
||||
{
|
||||
.name = "LEON3",
|
||||
.iu_version = 0xf3000000,
|
||||
.fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
|
||||
.mmu_version = 0xf3000000,
|
||||
.mmu_bm = 0x00000000,
|
||||
.mmu_ctpr_mask = 0xfffffffc,
|
||||
.mmu_cxr_mask = 0x000000ff,
|
||||
.mmu_sfsr_mask = 0xffffffff,
|
||||
.mmu_trcr_mask = 0xffffffff,
|
||||
.nwindows = 8,
|
||||
.features = CPU_DEFAULT_FEATURES | CPU_FEATURE_TA0_SHUTDOWN |
|
||||
CPU_FEATURE_ASR17 | CPU_FEATURE_CACHE_CTRL | CPU_FEATURE_POWERDOWN |
|
||||
CPU_FEATURE_CASA,
|
||||
},
|
||||
#endif
|
||||
};
|
||||
|
||||
static void sparc_cpu_set_pc(CPUState *cs, vaddr value)
|
||||
{
|
||||
SPARCCPU *cpu = SPARC_CPU(cs);
|
||||
|
||||
cpu->env.pc = value;
|
||||
cpu->env.npc = value + 4;
|
||||
}
|
||||
|
||||
static void sparc_cpu_synchronize_from_tb(CPUState *cs, TranslationBlock *tb)
|
||||
{
|
||||
SPARCCPU *cpu = SPARC_CPU(cs);
|
||||
|
||||
cpu->env.pc = tb->pc;
|
||||
cpu->env.npc = tb->cs_base;
|
||||
}
|
||||
|
||||
static bool sparc_cpu_has_work(CPUState *cs)
|
||||
{
|
||||
SPARCCPU *cpu = SPARC_CPU(cs);
|
||||
CPUSPARCState *env = &cpu->env;
|
||||
|
||||
return (cs->interrupt_request & CPU_INTERRUPT_HARD) &&
|
||||
cpu_interrupts_enabled(env);
|
||||
}
|
||||
|
||||
static void sparc_cpu_realizefn(struct uc_struct *uc, CPUState *dev)
|
||||
{
|
||||
CPUState *cs = CPU(dev);
|
||||
SPARCCPU *cpu = SPARC_CPU(dev);
|
||||
CPUSPARCState *env = &cpu->env;
|
||||
|
||||
env->version = env->def.iu_version;
|
||||
env->fsr = env->def.fpu_version;
|
||||
env->nwindows = env->def.nwindows;
|
||||
#if !defined(TARGET_SPARC64)
|
||||
env->mmuregs[0] |= env->def.mmu_version;
|
||||
cpu_sparc_set_id(env, 0);
|
||||
env->mxccregs[7] |= env->def.mxcc_version;
|
||||
#else
|
||||
env->mmu_version = env->def.mmu_version;
|
||||
env->maxtl = env->def.maxtl;
|
||||
env->version |= env->def.maxtl << 8;
|
||||
env->version |= env->def.nwindows - 1;
|
||||
#endif
|
||||
|
||||
cpu_exec_realizefn(cs);
|
||||
}
|
||||
|
||||
static void sparc_cpu_initfn(struct uc_struct *uc, CPUState *obj)
|
||||
{
|
||||
SPARCCPU *cpu = SPARC_CPU(obj);
|
||||
SPARCCPUClass *scc = SPARC_CPU_GET_CLASS(obj);
|
||||
CPUSPARCState *env = &cpu->env;
|
||||
|
||||
env->uc = uc;
|
||||
|
||||
cpu_set_cpustate_pointers(cpu);
|
||||
|
||||
if (scc->cpu_def) {
|
||||
env->def = *scc->cpu_def;
|
||||
}
|
||||
}
|
||||
|
||||
static void sparc_cpu_class_init(struct uc_struct *uc, CPUClass *oc)
|
||||
{
|
||||
SPARCCPUClass *scc = SPARC_CPU_CLASS(oc);
|
||||
CPUClass *cc = CPU_CLASS(oc);
|
||||
|
||||
/* parent class is CPUClass, parent_reset() is cpu_common_reset(). */
|
||||
scc->parent_reset = cc->reset;
|
||||
/* overwrite the CPUClass->reset to arch reset: x86_cpu_reset(). */
|
||||
cc->reset = sparc_cpu_reset;
|
||||
cc->has_work = sparc_cpu_has_work;
|
||||
cc->do_interrupt = sparc_cpu_do_interrupt;
|
||||
cc->cpu_exec_interrupt = sparc_cpu_exec_interrupt;
|
||||
cc->set_pc = sparc_cpu_set_pc;
|
||||
cc->synchronize_from_tb = sparc_cpu_synchronize_from_tb;
|
||||
cc->tlb_fill = sparc_cpu_tlb_fill;
|
||||
cc->do_unaligned_access = sparc_cpu_do_unaligned_access;
|
||||
cc->get_phys_page_debug = sparc_cpu_get_phys_page_debug;
|
||||
cc->tcg_initialize = sparc_tcg_init;
|
||||
}
|
||||
|
||||
SPARCCPU *cpu_sparc_init(struct uc_struct *uc, const char *cpu_model)
|
||||
{
|
||||
SPARCCPU *cpu;
|
||||
CPUState *cs;
|
||||
CPUClass *cc;
|
||||
SPARCCPUClass *scc;
|
||||
int i;
|
||||
|
||||
if (cpu_model == NULL) {
|
||||
#ifdef TARGET_SPARC64
|
||||
cpu_model = "Sun UltraSparc IV";
|
||||
#else
|
||||
cpu_model = "LEON3";
|
||||
#endif
|
||||
}
|
||||
|
||||
cpu = malloc(sizeof(*cpu));
|
||||
if (cpu == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
memset(cpu, 0, sizeof(*cpu));
|
||||
|
||||
cs = (CPUState *)cpu;
|
||||
cc = (CPUClass *)&cpu->cc;
|
||||
cs->cc = cc;
|
||||
cs->uc = uc;
|
||||
uc->cpu = cs;
|
||||
|
||||
/* init CPUClass */
|
||||
cpu_class_init(uc, cc);
|
||||
/* init SPARCCPUClass */
|
||||
sparc_cpu_class_init(uc, cc);
|
||||
/* init CPUState */
|
||||
cpu_common_initfn(uc, cs);
|
||||
/* init SPARC types scc->def */
|
||||
scc = SPARC_CPU_CLASS(cc);
|
||||
for (i = 0; i < ARRAY_SIZE(sparc_defs); i++) {
|
||||
if (strcmp(cpu_model, sparc_defs[i].name) == 0) {
|
||||
scc->cpu_def = &sparc_defs[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == ARRAY_SIZE(sparc_defs)) {
|
||||
free(cpu);
|
||||
return NULL;
|
||||
}
|
||||
/* init SPARCCPU */
|
||||
sparc_cpu_initfn(uc, cs);
|
||||
/* realize SPARCCPU */
|
||||
sparc_cpu_realizefn(uc, cs);
|
||||
/* realize CPUState */
|
||||
|
||||
// init address space
|
||||
cpu_address_space_init(cs, 0, cs->memory);
|
||||
|
||||
qemu_init_vcpu(cs);
|
||||
|
||||
return cpu;
|
||||
}
|
||||
820
qemu/target/sparc/cpu.h
Normal file
820
qemu/target/sparc/cpu.h
Normal file
@@ -0,0 +1,820 @@
|
||||
#ifndef SPARC_CPU_H
|
||||
#define SPARC_CPU_H
|
||||
|
||||
#include "qemu/bswap.h"
|
||||
#include "cpu-qom.h"
|
||||
#include "exec/cpu-defs.h"
|
||||
|
||||
#if !defined(TARGET_SPARC64)
|
||||
#define TARGET_DPREGS 16
|
||||
#else
|
||||
#define TARGET_DPREGS 32
|
||||
#endif
|
||||
|
||||
/*#define EXCP_INTERRUPT 0x100*/
|
||||
|
||||
/* Windowed register indexes. */
|
||||
enum {
|
||||
WREG_O0,
|
||||
WREG_O1,
|
||||
WREG_O2,
|
||||
WREG_O3,
|
||||
WREG_O4,
|
||||
WREG_O5,
|
||||
WREG_O6,
|
||||
WREG_O7,
|
||||
|
||||
WREG_L0,
|
||||
WREG_L1,
|
||||
WREG_L2,
|
||||
WREG_L3,
|
||||
WREG_L4,
|
||||
WREG_L5,
|
||||
WREG_L6,
|
||||
WREG_L7,
|
||||
|
||||
WREG_I0,
|
||||
WREG_I1,
|
||||
WREG_I2,
|
||||
WREG_I3,
|
||||
WREG_I4,
|
||||
WREG_I5,
|
||||
WREG_I6,
|
||||
WREG_I7,
|
||||
|
||||
WREG_SP = WREG_O6,
|
||||
WREG_FP = WREG_I6,
|
||||
};
|
||||
|
||||
/* trap definitions */
|
||||
#ifndef TARGET_SPARC64
|
||||
#define TT_TFAULT 0x01
|
||||
#define TT_ILL_INSN 0x02
|
||||
#define TT_PRIV_INSN 0x03
|
||||
#define TT_NFPU_INSN 0x04
|
||||
#define TT_WIN_OVF 0x05
|
||||
#define TT_WIN_UNF 0x06
|
||||
#define TT_UNALIGNED 0x07
|
||||
#define TT_FP_EXCP 0x08
|
||||
#define TT_DFAULT 0x09
|
||||
#define TT_TOVF 0x0a
|
||||
#define TT_EXTINT 0x10
|
||||
#define TT_CODE_ACCESS 0x21
|
||||
#define TT_UNIMP_FLUSH 0x25
|
||||
#define TT_DATA_ACCESS 0x29
|
||||
#define TT_DIV_ZERO 0x2a
|
||||
#define TT_NCP_INSN 0x24
|
||||
#define TT_TRAP 0x80
|
||||
#else
|
||||
#define TT_POWER_ON_RESET 0x01
|
||||
#define TT_TFAULT 0x08
|
||||
#define TT_CODE_ACCESS 0x0a
|
||||
#define TT_ILL_INSN 0x10
|
||||
#define TT_UNIMP_FLUSH TT_ILL_INSN
|
||||
#define TT_PRIV_INSN 0x11
|
||||
#define TT_NFPU_INSN 0x20
|
||||
#define TT_FP_EXCP 0x21
|
||||
#define TT_TOVF 0x23
|
||||
#define TT_CLRWIN 0x24
|
||||
#define TT_DIV_ZERO 0x28
|
||||
#define TT_DFAULT 0x30
|
||||
#define TT_DATA_ACCESS 0x32
|
||||
#define TT_UNALIGNED 0x34
|
||||
#define TT_PRIV_ACT 0x37
|
||||
#define TT_INSN_REAL_TRANSLATION_MISS 0x3e
|
||||
#define TT_DATA_REAL_TRANSLATION_MISS 0x3f
|
||||
#define TT_EXTINT 0x40
|
||||
#define TT_IVEC 0x60
|
||||
#define TT_TMISS 0x64
|
||||
#define TT_DMISS 0x68
|
||||
#define TT_DPROT 0x6c
|
||||
#define TT_SPILL 0x80
|
||||
#define TT_FILL 0xc0
|
||||
#define TT_WOTHER (1 << 5)
|
||||
#define TT_TRAP 0x100
|
||||
#define TT_HTRAP 0x180
|
||||
#endif
|
||||
|
||||
#define PSR_NEG_SHIFT 23
|
||||
#define PSR_NEG (1 << PSR_NEG_SHIFT)
|
||||
#define PSR_ZERO_SHIFT 22
|
||||
#define PSR_ZERO (1 << PSR_ZERO_SHIFT)
|
||||
#define PSR_OVF_SHIFT 21
|
||||
#define PSR_OVF (1 << PSR_OVF_SHIFT)
|
||||
#define PSR_CARRY_SHIFT 20
|
||||
#define PSR_CARRY (1 << PSR_CARRY_SHIFT)
|
||||
#define PSR_ICC (PSR_NEG|PSR_ZERO|PSR_OVF|PSR_CARRY)
|
||||
#if !defined(TARGET_SPARC64)
|
||||
#define PSR_EF (1<<12)
|
||||
#define PSR_PIL 0xf00
|
||||
#define PSR_S (1<<7)
|
||||
#define PSR_PS (1<<6)
|
||||
#define PSR_ET (1<<5)
|
||||
#define PSR_CWP 0x1f
|
||||
#endif
|
||||
|
||||
#define CC_SRC (env->cc_src)
|
||||
#define CC_SRC2 (env->cc_src2)
|
||||
#define CC_DST (env->cc_dst)
|
||||
#define CC_OP (env->cc_op)
|
||||
|
||||
/* Even though lazy evaluation of CPU condition codes tends to be less
|
||||
* important on RISC systems where condition codes are only updated
|
||||
* when explicitly requested, SPARC uses it to update 32-bit and 64-bit
|
||||
* condition codes.
|
||||
*/
|
||||
enum {
|
||||
CC_OP_DYNAMIC, /* must use dynamic code to get cc_op */
|
||||
CC_OP_FLAGS, /* all cc are back in status register */
|
||||
CC_OP_DIV, /* modify N, Z and V, C = 0*/
|
||||
CC_OP_ADD, /* modify all flags, CC_DST = res, CC_SRC = src1 */
|
||||
CC_OP_ADDX, /* modify all flags, CC_DST = res, CC_SRC = src1 */
|
||||
CC_OP_TADD, /* modify all flags, CC_DST = res, CC_SRC = src1 */
|
||||
CC_OP_TADDTV, /* modify all flags except V, CC_DST = res, CC_SRC = src1 */
|
||||
CC_OP_SUB, /* modify all flags, CC_DST = res, CC_SRC = src1 */
|
||||
CC_OP_SUBX, /* modify all flags, CC_DST = res, CC_SRC = src1 */
|
||||
CC_OP_TSUB, /* modify all flags, CC_DST = res, CC_SRC = src1 */
|
||||
CC_OP_TSUBTV, /* modify all flags except V, CC_DST = res, CC_SRC = src1 */
|
||||
CC_OP_LOGIC, /* modify N and Z, C = V = 0, CC_DST = res */
|
||||
CC_OP_NB,
|
||||
};
|
||||
|
||||
/* Trap base register */
|
||||
#define TBR_BASE_MASK 0xfffff000
|
||||
|
||||
#if defined(TARGET_SPARC64)
|
||||
#define PS_TCT (1<<12) /* UA2007, impl.dep. trap on control transfer */
|
||||
#define PS_IG (1<<11) /* v9, zero on UA2007 */
|
||||
#define PS_MG (1<<10) /* v9, zero on UA2007 */
|
||||
#define PS_CLE (1<<9) /* UA2007 */
|
||||
#define PS_TLE (1<<8) /* UA2007 */
|
||||
#define PS_RMO (1<<7)
|
||||
#define PS_RED (1<<5) /* v9, zero on UA2007 */
|
||||
#define PS_PEF (1<<4) /* enable fpu */
|
||||
#define PS_AM (1<<3) /* address mask */
|
||||
#define PS_PRIV (1<<2)
|
||||
#define PS_IE (1<<1)
|
||||
#define PS_AG (1<<0) /* v9, zero on UA2007 */
|
||||
|
||||
#define FPRS_FEF (1<<2)
|
||||
|
||||
#define HS_PRIV (1<<2)
|
||||
#endif
|
||||
|
||||
/* Fcc */
|
||||
#define FSR_RD1 (1ULL << 31)
|
||||
#define FSR_RD0 (1ULL << 30)
|
||||
#define FSR_RD_MASK (FSR_RD1 | FSR_RD0)
|
||||
#define FSR_RD_NEAREST 0
|
||||
#define FSR_RD_ZERO FSR_RD0
|
||||
#define FSR_RD_POS FSR_RD1
|
||||
#define FSR_RD_NEG (FSR_RD1 | FSR_RD0)
|
||||
|
||||
#define FSR_NVM (1ULL << 27)
|
||||
#define FSR_OFM (1ULL << 26)
|
||||
#define FSR_UFM (1ULL << 25)
|
||||
#define FSR_DZM (1ULL << 24)
|
||||
#define FSR_NXM (1ULL << 23)
|
||||
#define FSR_TEM_MASK (FSR_NVM | FSR_OFM | FSR_UFM | FSR_DZM | FSR_NXM)
|
||||
|
||||
#define FSR_NVA (1ULL << 9)
|
||||
#define FSR_OFA (1ULL << 8)
|
||||
#define FSR_UFA (1ULL << 7)
|
||||
#define FSR_DZA (1ULL << 6)
|
||||
#define FSR_NXA (1ULL << 5)
|
||||
#define FSR_AEXC_MASK (FSR_NVA | FSR_OFA | FSR_UFA | FSR_DZA | FSR_NXA)
|
||||
|
||||
#define FSR_NVC (1ULL << 4)
|
||||
#define FSR_OFC (1ULL << 3)
|
||||
#define FSR_UFC (1ULL << 2)
|
||||
#define FSR_DZC (1ULL << 1)
|
||||
#define FSR_NXC (1ULL << 0)
|
||||
#define FSR_CEXC_MASK (FSR_NVC | FSR_OFC | FSR_UFC | FSR_DZC | FSR_NXC)
|
||||
|
||||
#define FSR_FTT2 (1ULL << 16)
|
||||
#define FSR_FTT1 (1ULL << 15)
|
||||
#define FSR_FTT0 (1ULL << 14)
|
||||
//gcc warns about constant overflow for ~FSR_FTT_MASK
|
||||
//#define FSR_FTT_MASK (FSR_FTT2 | FSR_FTT1 | FSR_FTT0)
|
||||
#ifdef TARGET_SPARC64
|
||||
#define FSR_FTT_NMASK 0xfffffffffffe3fffULL
|
||||
#define FSR_FTT_CEXC_NMASK 0xfffffffffffe3fe0ULL
|
||||
#define FSR_LDFSR_OLDMASK 0x0000003f000fc000ULL
|
||||
#define FSR_LDXFSR_MASK 0x0000003fcfc00fffULL
|
||||
#define FSR_LDXFSR_OLDMASK 0x00000000000fc000ULL
|
||||
#else
|
||||
#define FSR_FTT_NMASK 0xfffe3fffULL
|
||||
#define FSR_FTT_CEXC_NMASK 0xfffe3fe0ULL
|
||||
#define FSR_LDFSR_OLDMASK 0x000fc000ULL
|
||||
#endif
|
||||
#define FSR_LDFSR_MASK 0xcfc00fffULL
|
||||
#define FSR_FTT_IEEE_EXCP (1ULL << 14)
|
||||
#define FSR_FTT_UNIMPFPOP (3ULL << 14)
|
||||
#define FSR_FTT_SEQ_ERROR (4ULL << 14)
|
||||
#define FSR_FTT_INVAL_FPR (6ULL << 14)
|
||||
|
||||
#define FSR_FCC1_SHIFT 11
|
||||
#define FSR_FCC1 (1ULL << FSR_FCC1_SHIFT)
|
||||
#define FSR_FCC0_SHIFT 10
|
||||
#define FSR_FCC0 (1ULL << FSR_FCC0_SHIFT)
|
||||
|
||||
/* MMU */
|
||||
#define MMU_E (1<<0)
|
||||
#define MMU_NF (1<<1)
|
||||
|
||||
#define PTE_ENTRYTYPE_MASK 3
|
||||
#define PTE_ACCESS_MASK 0x1c
|
||||
#define PTE_ACCESS_SHIFT 2
|
||||
#define PTE_PPN_SHIFT 7
|
||||
#define PTE_ADDR_MASK 0xffffff00
|
||||
|
||||
#define PG_ACCESSED_BIT 5
|
||||
#define PG_MODIFIED_BIT 6
|
||||
#define PG_CACHE_BIT 7
|
||||
|
||||
#define PG_ACCESSED_MASK (1 << PG_ACCESSED_BIT)
|
||||
#define PG_MODIFIED_MASK (1 << PG_MODIFIED_BIT)
|
||||
#define PG_CACHE_MASK (1 << PG_CACHE_BIT)
|
||||
|
||||
/* 3 <= NWINDOWS <= 32. */
|
||||
#define MIN_NWINDOWS 3
|
||||
#define MAX_NWINDOWS 32
|
||||
|
||||
#ifdef TARGET_SPARC64
|
||||
typedef struct trap_state {
|
||||
uint64_t tpc;
|
||||
uint64_t tnpc;
|
||||
uint64_t tstate;
|
||||
uint32_t tt;
|
||||
} trap_state;
|
||||
#endif
|
||||
#define TARGET_INSN_START_EXTRA_WORDS 1
|
||||
|
||||
struct sparc_def_t {
|
||||
const char *name;
|
||||
target_ulong iu_version;
|
||||
uint32_t fpu_version;
|
||||
uint32_t mmu_version;
|
||||
uint32_t mmu_bm;
|
||||
uint32_t mmu_ctpr_mask;
|
||||
uint32_t mmu_cxr_mask;
|
||||
uint32_t mmu_sfsr_mask;
|
||||
uint32_t mmu_trcr_mask;
|
||||
uint32_t mxcc_version;
|
||||
uint32_t features;
|
||||
uint32_t nwindows;
|
||||
uint32_t maxtl;
|
||||
};
|
||||
|
||||
#define CPU_FEATURE_FLOAT (1 << 0)
|
||||
#define CPU_FEATURE_FLOAT128 (1 << 1)
|
||||
#define CPU_FEATURE_SWAP (1 << 2)
|
||||
#define CPU_FEATURE_MUL (1 << 3)
|
||||
#define CPU_FEATURE_DIV (1 << 4)
|
||||
#define CPU_FEATURE_FLUSH (1 << 5)
|
||||
#define CPU_FEATURE_FSQRT (1 << 6)
|
||||
#define CPU_FEATURE_FMUL (1 << 7)
|
||||
#define CPU_FEATURE_VIS1 (1 << 8)
|
||||
#define CPU_FEATURE_VIS2 (1 << 9)
|
||||
#define CPU_FEATURE_FSMULD (1 << 10)
|
||||
#define CPU_FEATURE_HYPV (1 << 11)
|
||||
#define CPU_FEATURE_CMT (1 << 12)
|
||||
#define CPU_FEATURE_GL (1 << 13)
|
||||
#define CPU_FEATURE_TA0_SHUTDOWN (1 << 14) /* Shutdown on "ta 0x0" */
|
||||
#define CPU_FEATURE_ASR17 (1 << 15)
|
||||
#define CPU_FEATURE_CACHE_CTRL (1 << 16)
|
||||
#define CPU_FEATURE_POWERDOWN (1 << 17)
|
||||
#define CPU_FEATURE_CASA (1 << 18)
|
||||
|
||||
#ifndef TARGET_SPARC64
|
||||
#define CPU_DEFAULT_FEATURES (CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | \
|
||||
CPU_FEATURE_MUL | CPU_FEATURE_DIV | \
|
||||
CPU_FEATURE_FLUSH | CPU_FEATURE_FSQRT | \
|
||||
CPU_FEATURE_FMUL | CPU_FEATURE_FSMULD)
|
||||
#else
|
||||
#define CPU_DEFAULT_FEATURES (CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | \
|
||||
CPU_FEATURE_MUL | CPU_FEATURE_DIV | \
|
||||
CPU_FEATURE_FLUSH | CPU_FEATURE_FSQRT | \
|
||||
CPU_FEATURE_FMUL | CPU_FEATURE_VIS1 | \
|
||||
CPU_FEATURE_VIS2 | CPU_FEATURE_FSMULD | \
|
||||
CPU_FEATURE_CASA)
|
||||
enum {
|
||||
mmu_us_12, // Ultrasparc < III (64 entry TLB)
|
||||
mmu_us_3, // Ultrasparc III (512 entry TLB)
|
||||
mmu_us_4, // Ultrasparc IV (several TLBs, 32 and 256MB pages)
|
||||
mmu_sun4v, // T1, T2
|
||||
};
|
||||
#endif
|
||||
|
||||
#define TTE_VALID_BIT (1ULL << 63)
|
||||
#define TTE_NFO_BIT (1ULL << 60)
|
||||
#define TTE_IE_BIT (1ULL << 59)
|
||||
#define TTE_USED_BIT (1ULL << 41)
|
||||
#define TTE_LOCKED_BIT (1ULL << 6)
|
||||
#define TTE_SIDEEFFECT_BIT (1ULL << 3)
|
||||
#define TTE_PRIV_BIT (1ULL << 2)
|
||||
#define TTE_W_OK_BIT (1ULL << 1)
|
||||
#define TTE_GLOBAL_BIT (1ULL << 0)
|
||||
|
||||
#define TTE_NFO_BIT_UA2005 (1ULL << 62)
|
||||
#define TTE_USED_BIT_UA2005 (1ULL << 47)
|
||||
#define TTE_LOCKED_BIT_UA2005 (1ULL << 61)
|
||||
#define TTE_SIDEEFFECT_BIT_UA2005 (1ULL << 11)
|
||||
#define TTE_PRIV_BIT_UA2005 (1ULL << 8)
|
||||
#define TTE_W_OK_BIT_UA2005 (1ULL << 6)
|
||||
|
||||
#define TTE_IS_VALID(tte) ((tte) & TTE_VALID_BIT)
|
||||
#define TTE_IS_NFO(tte) ((tte) & TTE_NFO_BIT)
|
||||
#define TTE_IS_IE(tte) ((tte) & TTE_IE_BIT)
|
||||
#define TTE_IS_USED(tte) ((tte) & TTE_USED_BIT)
|
||||
#define TTE_IS_LOCKED(tte) ((tte) & TTE_LOCKED_BIT)
|
||||
#define TTE_IS_SIDEEFFECT(tte) ((tte) & TTE_SIDEEFFECT_BIT)
|
||||
#define TTE_IS_SIDEEFFECT_UA2005(tte) ((tte) & TTE_SIDEEFFECT_BIT_UA2005)
|
||||
#define TTE_IS_PRIV(tte) ((tte) & TTE_PRIV_BIT)
|
||||
#define TTE_IS_W_OK(tte) ((tte) & TTE_W_OK_BIT)
|
||||
|
||||
#define TTE_IS_NFO_UA2005(tte) ((tte) & TTE_NFO_BIT_UA2005)
|
||||
#define TTE_IS_USED_UA2005(tte) ((tte) & TTE_USED_BIT_UA2005)
|
||||
#define TTE_IS_LOCKED_UA2005(tte) ((tte) & TTE_LOCKED_BIT_UA2005)
|
||||
#define TTE_IS_SIDEEFFECT_UA2005(tte) ((tte) & TTE_SIDEEFFECT_BIT_UA2005)
|
||||
#define TTE_IS_PRIV_UA2005(tte) ((tte) & TTE_PRIV_BIT_UA2005)
|
||||
#define TTE_IS_W_OK_UA2005(tte) ((tte) & TTE_W_OK_BIT_UA2005)
|
||||
|
||||
#define TTE_IS_GLOBAL(tte) ((tte) & TTE_GLOBAL_BIT)
|
||||
|
||||
#define TTE_SET_USED(tte) ((tte) |= TTE_USED_BIT)
|
||||
#define TTE_SET_UNUSED(tte) ((tte) &= ~TTE_USED_BIT)
|
||||
|
||||
#define TTE_PGSIZE(tte) (((tte) >> 61) & 3ULL)
|
||||
#define TTE_PGSIZE_UA2005(tte) ((tte) & 7ULL)
|
||||
#define TTE_PA(tte) ((tte) & 0x1ffffffe000ULL)
|
||||
|
||||
/* UltraSPARC T1 specific */
|
||||
#define TLB_UST1_IS_REAL_BIT (1ULL << 9) /* Real translation entry */
|
||||
#define TLB_UST1_IS_SUN4V_BIT (1ULL << 10) /* sun4u/sun4v TTE format switch */
|
||||
|
||||
#define SFSR_NF_BIT (1ULL << 24) /* JPS1 NoFault */
|
||||
#define SFSR_TM_BIT (1ULL << 15) /* JPS1 TLB Miss */
|
||||
#define SFSR_FT_VA_IMMU_BIT (1ULL << 13) /* USIIi VA out of range (IMMU) */
|
||||
#define SFSR_FT_VA_DMMU_BIT (1ULL << 12) /* USIIi VA out of range (DMMU) */
|
||||
#define SFSR_FT_NFO_BIT (1ULL << 11) /* NFO page access */
|
||||
#define SFSR_FT_ILL_BIT (1ULL << 10) /* illegal LDA/STA ASI */
|
||||
#define SFSR_FT_ATOMIC_BIT (1ULL << 9) /* atomic op on noncacheable area */
|
||||
#define SFSR_FT_NF_E_BIT (1ULL << 8) /* NF access on side effect area */
|
||||
#define SFSR_FT_PRIV_BIT (1ULL << 7) /* privilege violation */
|
||||
#define SFSR_PR_BIT (1ULL << 3) /* privilege mode */
|
||||
#define SFSR_WRITE_BIT (1ULL << 2) /* write access mode */
|
||||
#define SFSR_OW_BIT (1ULL << 1) /* status overwritten */
|
||||
#define SFSR_VALID_BIT (1ULL << 0) /* status valid */
|
||||
|
||||
#define SFSR_ASI_SHIFT 16 /* 23:16 ASI value */
|
||||
#define SFSR_ASI_MASK (0xffULL << SFSR_ASI_SHIFT)
|
||||
#define SFSR_CT_PRIMARY (0ULL << 4) /* 5:4 context type */
|
||||
#define SFSR_CT_SECONDARY (1ULL << 4)
|
||||
#define SFSR_CT_NUCLEUS (2ULL << 4)
|
||||
#define SFSR_CT_NOTRANS (3ULL << 4)
|
||||
#define SFSR_CT_MASK (3ULL << 4)
|
||||
|
||||
/* Leon3 cache control */
|
||||
|
||||
/* Cache control: emulate the behavior of cache control registers but without
|
||||
any effect on the emulated */
|
||||
|
||||
#define CACHE_STATE_MASK 0x3
|
||||
#define CACHE_DISABLED 0x0
|
||||
#define CACHE_FROZEN 0x1
|
||||
#define CACHE_ENABLED 0x3
|
||||
|
||||
/* Cache Control register fields */
|
||||
|
||||
#define CACHE_CTRL_IF (1 << 4) /* Instruction Cache Freeze on Interrupt */
|
||||
#define CACHE_CTRL_DF (1 << 5) /* Data Cache Freeze on Interrupt */
|
||||
#define CACHE_CTRL_DP (1 << 14) /* Data cache flush pending */
|
||||
#define CACHE_CTRL_IP (1 << 15) /* Instruction cache flush pending */
|
||||
#define CACHE_CTRL_IB (1 << 16) /* Instruction burst fetch */
|
||||
#define CACHE_CTRL_FI (1 << 21) /* Flush Instruction cache (Write only) */
|
||||
#define CACHE_CTRL_FD (1 << 22) /* Flush Data cache (Write only) */
|
||||
#define CACHE_CTRL_DS (1 << 23) /* Data cache snoop enable */
|
||||
|
||||
#define CONVERT_BIT(X, SRC, DST) \
|
||||
(SRC > DST ? (X) / (SRC / DST) & (DST) : ((X) & SRC) * (DST / SRC))
|
||||
|
||||
typedef struct SparcTLBEntry {
|
||||
uint64_t tag;
|
||||
uint64_t tte;
|
||||
} SparcTLBEntry;
|
||||
|
||||
struct CPUTimer
|
||||
{
|
||||
const char *name;
|
||||
uint32_t frequency;
|
||||
uint32_t disabled;
|
||||
uint64_t disabled_mask;
|
||||
uint32_t npt;
|
||||
uint64_t npt_mask;
|
||||
int64_t clock_offset;
|
||||
QEMUTimer *qtimer;
|
||||
};
|
||||
|
||||
typedef struct CPUTimer CPUTimer;
|
||||
|
||||
typedef struct CPUSPARCState CPUSPARCState;
|
||||
#if defined(TARGET_SPARC64)
|
||||
typedef union {
|
||||
uint64_t mmuregs[16];
|
||||
struct {
|
||||
uint64_t tsb_tag_target;
|
||||
uint64_t mmu_primary_context;
|
||||
uint64_t mmu_secondary_context;
|
||||
uint64_t sfsr;
|
||||
uint64_t sfar;
|
||||
uint64_t tsb;
|
||||
uint64_t tag_access;
|
||||
uint64_t virtual_watchpoint;
|
||||
uint64_t physical_watchpoint;
|
||||
uint64_t sun4v_ctx_config[2];
|
||||
uint64_t sun4v_tsb_pointers[4];
|
||||
};
|
||||
} SparcV9MMU;
|
||||
#endif
|
||||
struct CPUSPARCState {
|
||||
target_ulong gregs[8]; /* general registers */
|
||||
target_ulong *regwptr; /* pointer to current register window */
|
||||
target_ulong pc; /* program counter */
|
||||
target_ulong npc; /* next program counter */
|
||||
target_ulong y; /* multiply/divide register */
|
||||
|
||||
/* emulator internal flags handling */
|
||||
target_ulong cc_src, cc_src2;
|
||||
target_ulong cc_dst;
|
||||
uint32_t cc_op;
|
||||
|
||||
target_ulong cond; /* conditional branch result (XXX: save it in a
|
||||
temporary register when possible) */
|
||||
|
||||
uint32_t psr; /* processor state register */
|
||||
target_ulong fsr; /* FPU state register */
|
||||
CPU_DoubleU fpr[TARGET_DPREGS]; /* floating point registers */
|
||||
uint32_t cwp; /* index of current register window (extracted
|
||||
from PSR) */
|
||||
#if !defined(TARGET_SPARC64) || defined(TARGET_ABI32)
|
||||
uint32_t wim; /* window invalid mask */
|
||||
#endif
|
||||
target_ulong tbr; /* trap base register */
|
||||
#if !defined(TARGET_SPARC64)
|
||||
int psrs; /* supervisor mode (extracted from PSR) */
|
||||
int psrps; /* previous supervisor mode */
|
||||
int psret; /* enable traps */
|
||||
#endif
|
||||
uint32_t psrpil; /* interrupt blocking level */
|
||||
uint32_t pil_in; /* incoming interrupt level bitmap */
|
||||
#if !defined(TARGET_SPARC64)
|
||||
int psref; /* enable fpu */
|
||||
#endif
|
||||
int interrupt_index;
|
||||
/* NOTE: we allow 8 more registers to handle wrapping */
|
||||
target_ulong regbase[MAX_NWINDOWS * 16 + 8];
|
||||
|
||||
/* Fields up to this point are cleared by a CPU reset */
|
||||
#ifdef _MSC_VER
|
||||
int end_reset_fields;
|
||||
#else
|
||||
struct {} end_reset_fields;
|
||||
#endif
|
||||
|
||||
/* Fields from here on are preserved across CPU reset. */
|
||||
target_ulong version;
|
||||
uint32_t nwindows;
|
||||
|
||||
/* MMU regs */
|
||||
#if defined(TARGET_SPARC64)
|
||||
uint64_t lsu;
|
||||
#define DMMU_E 0x8
|
||||
#define IMMU_E 0x4
|
||||
SparcV9MMU immu;
|
||||
SparcV9MMU dmmu;
|
||||
SparcTLBEntry itlb[64];
|
||||
SparcTLBEntry dtlb[64];
|
||||
uint32_t mmu_version;
|
||||
#else
|
||||
uint32_t mmuregs[32];
|
||||
uint64_t mxccdata[4];
|
||||
uint64_t mxccregs[8];
|
||||
uint32_t mmubpctrv, mmubpctrc, mmubpctrs;
|
||||
uint64_t mmubpaction;
|
||||
uint64_t mmubpregs[4];
|
||||
uint64_t prom_addr;
|
||||
#endif
|
||||
/* temporary float registers */
|
||||
float128 qt0, qt1;
|
||||
float_status fp_status;
|
||||
#if defined(TARGET_SPARC64)
|
||||
#define MAXTL_MAX 8
|
||||
#define MAXTL_MASK (MAXTL_MAX - 1)
|
||||
trap_state ts[MAXTL_MAX];
|
||||
uint32_t xcc; /* Extended integer condition codes */
|
||||
uint32_t asi;
|
||||
uint32_t pstate;
|
||||
uint32_t tl;
|
||||
uint32_t maxtl;
|
||||
uint32_t cansave, canrestore, otherwin, wstate, cleanwin;
|
||||
uint64_t agregs[8]; /* alternate general registers */
|
||||
uint64_t bgregs[8]; /* backup for normal global registers */
|
||||
uint64_t igregs[8]; /* interrupt general registers */
|
||||
uint64_t mgregs[8]; /* mmu general registers */
|
||||
uint64_t glregs[8 * MAXTL_MAX];
|
||||
uint64_t fprs;
|
||||
uint64_t tick_cmpr, stick_cmpr;
|
||||
CPUTimer *tick, *stick;
|
||||
#define TICK_NPT_MASK 0x8000000000000000ULL
|
||||
#define TICK_INT_DIS 0x8000000000000000ULL
|
||||
uint64_t gsr;
|
||||
uint32_t gl; // UA2005
|
||||
/* UA 2005 hyperprivileged registers */
|
||||
uint64_t hpstate, htstate[MAXTL_MAX], hintp, htba, hver, hstick_cmpr, ssr;
|
||||
uint64_t scratch[8];
|
||||
CPUTimer *hstick; // UA 2005
|
||||
/* Interrupt vector registers */
|
||||
uint64_t ivec_status;
|
||||
uint64_t ivec_data[3];
|
||||
uint32_t softint;
|
||||
#define SOFTINT_TIMER 1
|
||||
#define SOFTINT_STIMER (1 << 16)
|
||||
#define SOFTINT_INTRMASK (0xFFFE)
|
||||
#define SOFTINT_REG_MASK (SOFTINT_STIMER|SOFTINT_INTRMASK|SOFTINT_TIMER)
|
||||
#endif
|
||||
sparc_def_t def;
|
||||
|
||||
/* Leon3 cache control */
|
||||
uint32_t cache_control;
|
||||
|
||||
void *irq_manager;
|
||||
void (*qemu_irq_ack)(CPUSPARCState *env, void *irq_manager, int intno);
|
||||
|
||||
// Unicorn engine
|
||||
struct uc_struct *uc;
|
||||
};
|
||||
|
||||
/**
|
||||
* SPARCCPU:
|
||||
* @env: #CPUSPARCState
|
||||
*
|
||||
* A SPARC CPU.
|
||||
*/
|
||||
struct SPARCCPU {
|
||||
/*< private >*/
|
||||
CPUState parent_obj;
|
||||
/*< public >*/
|
||||
|
||||
CPUNegativeOffsetState neg;
|
||||
CPUSPARCState env;
|
||||
|
||||
struct SPARCCPUClass cc;
|
||||
};
|
||||
|
||||
|
||||
void sparc_cpu_do_interrupt(CPUState *cpu);
|
||||
hwaddr sparc_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
|
||||
void QEMU_NORETURN sparc_cpu_do_unaligned_access(CPUState *cpu, vaddr addr,
|
||||
MMUAccessType access_type,
|
||||
int mmu_idx,
|
||||
uintptr_t retaddr);
|
||||
#ifdef _MSC_VER
|
||||
void cpu_raise_exception_ra(CPUSPARCState *, int, uintptr_t);
|
||||
#else
|
||||
void cpu_raise_exception_ra(CPUSPARCState *, int, uintptr_t) QEMU_NORETURN;
|
||||
#endif
|
||||
|
||||
#ifndef NO_CPU_IO_DEFS
|
||||
/* cpu_init.c */
|
||||
void cpu_sparc_set_id(CPUSPARCState *env, unsigned int cpu);
|
||||
void sparc_cpu_list(void);
|
||||
/* mmu_helper.c */
|
||||
bool sparc_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
||||
MMUAccessType access_type, int mmu_idx,
|
||||
bool probe, uintptr_t retaddr);
|
||||
target_ulong mmu_probe(CPUSPARCState *env, target_ulong address, int mmulev);
|
||||
|
||||
#if !defined(TARGET_SPARC64)
|
||||
int sparc_cpu_memory_rw_debug(CPUState *cpu, vaddr addr,
|
||||
uint8_t *buf, int len, bool is_write);
|
||||
#endif
|
||||
|
||||
|
||||
/* translate.c */
|
||||
void sparc_tcg_init(struct uc_struct *uc);
|
||||
|
||||
/* cpu-exec.c */
|
||||
|
||||
/* win_helper.c */
|
||||
target_ulong cpu_get_psr(CPUSPARCState *env1);
|
||||
void cpu_put_psr(CPUSPARCState *env1, target_ulong val);
|
||||
void cpu_put_psr_raw(CPUSPARCState *env1, target_ulong val);
|
||||
#ifdef TARGET_SPARC64
|
||||
target_ulong cpu_get_ccr(CPUSPARCState *env1);
|
||||
void cpu_put_ccr(CPUSPARCState *env1, target_ulong val);
|
||||
target_ulong cpu_get_cwp64(CPUSPARCState *env1);
|
||||
void cpu_put_cwp64(CPUSPARCState *env1, int cwp);
|
||||
void cpu_change_pstate(CPUSPARCState *env1, uint32_t new_pstate);
|
||||
void cpu_gl_switch_gregs(CPUSPARCState *env, uint32_t new_gl);
|
||||
#endif
|
||||
int cpu_cwp_inc(CPUSPARCState *env1, int cwp);
|
||||
int cpu_cwp_dec(CPUSPARCState *env1, int cwp);
|
||||
void cpu_set_cwp(CPUSPARCState *env1, int new_cwp);
|
||||
|
||||
/* int_helper.c */
|
||||
void leon3_irq_manager(CPUSPARCState *env, void *irq_manager, int intno);
|
||||
|
||||
/* leon3.c */
|
||||
// void leon3_irq_ack(void *irq_manager, int intno);
|
||||
|
||||
#if defined (TARGET_SPARC64)
|
||||
|
||||
static inline int compare_masked(uint64_t x, uint64_t y, uint64_t mask)
|
||||
{
|
||||
return (x & mask) == (y & mask);
|
||||
}
|
||||
|
||||
#define MMU_CONTEXT_BITS 13
|
||||
#define MMU_CONTEXT_MASK ((1 << MMU_CONTEXT_BITS) - 1)
|
||||
|
||||
static inline int tlb_compare_context(const SparcTLBEntry *tlb,
|
||||
uint64_t context)
|
||||
{
|
||||
return compare_masked(context, tlb->tag, MMU_CONTEXT_MASK);
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* cpu-exec.c */
|
||||
void sparc_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr,
|
||||
vaddr addr, unsigned size,
|
||||
MMUAccessType access_type,
|
||||
int mmu_idx, MemTxAttrs attrs,
|
||||
MemTxResult response, uintptr_t retaddr);
|
||||
#if defined(TARGET_SPARC64)
|
||||
hwaddr cpu_get_phys_page_nofault(CPUSPARCState *env, target_ulong addr,
|
||||
int mmu_idx);
|
||||
#endif
|
||||
|
||||
int cpu_sparc_signal_handler(int host_signum, void *pinfo, void *puc);
|
||||
|
||||
#define SPARC_CPU_TYPE_SUFFIX "-" TYPE_SPARC_CPU
|
||||
#define SPARC_CPU_TYPE_NAME(model) model SPARC_CPU_TYPE_SUFFIX
|
||||
#define CPU_RESOLVING_TYPE TYPE_SPARC_CPU
|
||||
|
||||
#define cpu_signal_handler cpu_sparc_signal_handler
|
||||
#define cpu_list sparc_cpu_list
|
||||
|
||||
/* MMU modes definitions */
|
||||
#if defined (TARGET_SPARC64)
|
||||
#define MMU_USER_IDX 0
|
||||
#define MMU_USER_SECONDARY_IDX 1
|
||||
#define MMU_KERNEL_IDX 2
|
||||
#define MMU_KERNEL_SECONDARY_IDX 3
|
||||
#define MMU_NUCLEUS_IDX 4
|
||||
#define MMU_PHYS_IDX 5
|
||||
#else
|
||||
#define MMU_USER_IDX 0
|
||||
#define MMU_KERNEL_IDX 1
|
||||
#define MMU_PHYS_IDX 2
|
||||
#endif
|
||||
|
||||
#if defined (TARGET_SPARC64)
|
||||
static inline int cpu_has_hypervisor(CPUSPARCState *env1)
|
||||
{
|
||||
return env1->def.features & CPU_FEATURE_HYPV;
|
||||
}
|
||||
|
||||
static inline int cpu_hypervisor_mode(CPUSPARCState *env1)
|
||||
{
|
||||
return cpu_has_hypervisor(env1) && (env1->hpstate & HS_PRIV);
|
||||
}
|
||||
|
||||
static inline int cpu_supervisor_mode(CPUSPARCState *env1)
|
||||
{
|
||||
return env1->pstate & PS_PRIV;
|
||||
}
|
||||
#else
|
||||
static inline int cpu_supervisor_mode(CPUSPARCState *env1)
|
||||
{
|
||||
return env1->psrs;
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline int cpu_mmu_index(CPUSPARCState *env, bool ifetch)
|
||||
{
|
||||
#if !defined(TARGET_SPARC64)
|
||||
if ((env->mmuregs[0] & MMU_E) == 0) { /* MMU disabled */
|
||||
return MMU_PHYS_IDX;
|
||||
} else {
|
||||
return env->psrs;
|
||||
}
|
||||
#else
|
||||
/* IMMU or DMMU disabled. */
|
||||
if (ifetch
|
||||
? (env->lsu & IMMU_E) == 0 || (env->pstate & PS_RED) != 0
|
||||
: (env->lsu & DMMU_E) == 0) {
|
||||
return MMU_PHYS_IDX;
|
||||
} else if (cpu_hypervisor_mode(env)) {
|
||||
return MMU_PHYS_IDX;
|
||||
} else if (env->tl > 0) {
|
||||
return MMU_NUCLEUS_IDX;
|
||||
} else if (cpu_supervisor_mode(env)) {
|
||||
return MMU_KERNEL_IDX;
|
||||
} else {
|
||||
return MMU_USER_IDX;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline int cpu_interrupts_enabled(CPUSPARCState *env1)
|
||||
{
|
||||
#if !defined (TARGET_SPARC64)
|
||||
if (env1->psret != 0)
|
||||
return 1;
|
||||
#else
|
||||
if ((env1->pstate & PS_IE) && !cpu_hypervisor_mode(env1)) {
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int cpu_pil_allowed(CPUSPARCState *env1, int pil)
|
||||
{
|
||||
#if !defined(TARGET_SPARC64)
|
||||
/* level 15 is non-maskable on sparc v8 */
|
||||
return pil == 15 || pil > env1->psrpil;
|
||||
#else
|
||||
return pil > env1->psrpil;
|
||||
#endif
|
||||
}
|
||||
|
||||
typedef CPUSPARCState CPUArchState;
|
||||
typedef SPARCCPU ArchCPU;
|
||||
|
||||
#include "exec/cpu-all.h"
|
||||
|
||||
#ifdef TARGET_SPARC64
|
||||
/* sun4u.c */
|
||||
void cpu_tick_set_count(CPUTimer *timer, uint64_t count);
|
||||
uint64_t cpu_tick_get_count(CPUTimer *timer);
|
||||
void cpu_tick_set_limit(CPUTimer *timer, uint64_t limit);
|
||||
trap_state* cpu_tsptr(CPUSPARCState* env);
|
||||
#endif
|
||||
|
||||
#define TB_FLAG_MMU_MASK 7
|
||||
#define TB_FLAG_FPU_ENABLED (1 << 4)
|
||||
#define TB_FLAG_AM_ENABLED (1 << 5)
|
||||
#define TB_FLAG_SUPER (1 << 6)
|
||||
#define TB_FLAG_HYPER (1 << 7)
|
||||
#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 *pflags)
|
||||
{
|
||||
uint32_t flags;
|
||||
*pc = env->pc;
|
||||
*cs_base = env->npc;
|
||||
flags = cpu_mmu_index(env, false);
|
||||
if (cpu_supervisor_mode(env)) {
|
||||
flags |= TB_FLAG_SUPER;
|
||||
}
|
||||
#ifdef TARGET_SPARC64
|
||||
if (env->pstate & PS_AM) {
|
||||
flags |= TB_FLAG_AM_ENABLED;
|
||||
}
|
||||
if ((env->def.features & CPU_FEATURE_FLOAT)
|
||||
&& (env->pstate & PS_PEF)
|
||||
&& (env->fprs & FPRS_FEF)) {
|
||||
flags |= TB_FLAG_FPU_ENABLED;
|
||||
}
|
||||
flags |= env->asi << TB_FLAG_ASI_SHIFT;
|
||||
#else
|
||||
if ((env->def.features & CPU_FEATURE_FLOAT) && env->psref) {
|
||||
flags |= TB_FLAG_FPU_ENABLED;
|
||||
}
|
||||
#endif
|
||||
*pflags = flags;
|
||||
}
|
||||
|
||||
static inline bool tb_fpu_enabled(int tb_flags)
|
||||
{
|
||||
return tb_flags & TB_FLAG_FPU_ENABLED;
|
||||
}
|
||||
|
||||
static inline bool tb_am_enabled(int tb_flags)
|
||||
{
|
||||
#ifndef TARGET_SPARC64
|
||||
return false;
|
||||
#else
|
||||
return tb_flags & TB_FLAG_AM_ENABLED;
|
||||
#endif
|
||||
}
|
||||
|
||||
SPARCCPU *cpu_sparc_init(struct uc_struct *uc, const char *cpu_model);
|
||||
|
||||
#endif
|
||||
401
qemu/target/sparc/fop_helper.c
Normal file
401
qemu/target/sparc/fop_helper.c
Normal file
@@ -0,0 +1,401 @@
|
||||
/*
|
||||
* FPU op helpers
|
||||
*
|
||||
* Copyright (c) 2003-2005 Fabrice Bellard
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "cpu.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "exec/helper-proto.h"
|
||||
#include "fpu/softfloat.h"
|
||||
|
||||
#define QT0 (env->qt0)
|
||||
#define QT1 (env->qt1)
|
||||
|
||||
static target_ulong do_check_ieee_exceptions(CPUSPARCState *env, uintptr_t ra)
|
||||
{
|
||||
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);
|
||||
|
||||
/* Copy IEEE 754 flags into FSR */
|
||||
if (status & float_flag_invalid) {
|
||||
fsr |= FSR_NVC;
|
||||
}
|
||||
if (status & float_flag_overflow) {
|
||||
fsr |= FSR_OFC;
|
||||
}
|
||||
if (status & float_flag_underflow) {
|
||||
fsr |= FSR_UFC;
|
||||
}
|
||||
if (status & float_flag_divbyzero) {
|
||||
fsr |= FSR_DZC;
|
||||
}
|
||||
if (status & float_flag_inexact) {
|
||||
fsr |= FSR_NXC;
|
||||
}
|
||||
|
||||
if ((fsr & FSR_CEXC_MASK) & ((fsr & FSR_TEM_MASK) >> 23)) {
|
||||
CPUState *cs = env_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 */
|
||||
fsr |= (fsr & FSR_CEXC_MASK) << 5;
|
||||
}
|
||||
}
|
||||
|
||||
return fsr;
|
||||
}
|
||||
|
||||
target_ulong helper_check_ieee_exceptions(CPUSPARCState *env)
|
||||
{
|
||||
return do_check_ieee_exceptions(env, GETPC());
|
||||
}
|
||||
|
||||
#define F_HELPER(name, p) void helper_f##name##p(CPUSPARCState *env)
|
||||
|
||||
#define F_BINOP(name) \
|
||||
float32 helper_f ## name ## s (CPUSPARCState *env, float32 src1, \
|
||||
float32 src2) \
|
||||
{ \
|
||||
return float32_ ## name (src1, src2, &env->fp_status); \
|
||||
} \
|
||||
float64 helper_f ## name ## d (CPUSPARCState * env, float64 src1,\
|
||||
float64 src2) \
|
||||
{ \
|
||||
return float64_ ## name (src1, src2, &env->fp_status); \
|
||||
} \
|
||||
F_HELPER(name, q) \
|
||||
{ \
|
||||
QT0 = float128_ ## name (QT0, QT1, &env->fp_status); \
|
||||
}
|
||||
|
||||
F_BINOP(add);
|
||||
F_BINOP(sub);
|
||||
F_BINOP(mul);
|
||||
F_BINOP(div);
|
||||
#undef F_BINOP
|
||||
|
||||
float64 helper_fsmuld(CPUSPARCState *env, float32 src1, float32 src2)
|
||||
{
|
||||
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)
|
||||
{
|
||||
QT0 = float128_mul(float64_to_float128(src1, &env->fp_status),
|
||||
float64_to_float128(src2, &env->fp_status),
|
||||
&env->fp_status);
|
||||
}
|
||||
|
||||
float32 helper_fnegs(float32 src)
|
||||
{
|
||||
return float32_chs(src);
|
||||
}
|
||||
|
||||
#ifdef TARGET_SPARC64
|
||||
float64 helper_fnegd(float64 src)
|
||||
{
|
||||
return float64_chs(src);
|
||||
}
|
||||
|
||||
F_HELPER(neg, q)
|
||||
{
|
||||
QT0 = float128_chs(QT1);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Integer to float conversion. */
|
||||
float32 helper_fitos(CPUSPARCState *env, int32_t src)
|
||||
{
|
||||
return int32_to_float32(src, &env->fp_status);
|
||||
}
|
||||
|
||||
float64 helper_fitod(CPUSPARCState *env, int32_t src)
|
||||
{
|
||||
return int32_to_float64(src, &env->fp_status);
|
||||
}
|
||||
|
||||
void helper_fitoq(CPUSPARCState *env, int32_t src)
|
||||
{
|
||||
QT0 = int32_to_float128(src, &env->fp_status);
|
||||
}
|
||||
|
||||
#ifdef TARGET_SPARC64
|
||||
float32 helper_fxtos(CPUSPARCState *env, int64_t src)
|
||||
{
|
||||
return int64_to_float32(src, &env->fp_status);
|
||||
}
|
||||
|
||||
float64 helper_fxtod(CPUSPARCState *env, int64_t src)
|
||||
{
|
||||
return int64_to_float64(src, &env->fp_status);
|
||||
}
|
||||
|
||||
void helper_fxtoq(CPUSPARCState *env, int64_t src)
|
||||
{
|
||||
QT0 = int64_to_float128(src, &env->fp_status);
|
||||
}
|
||||
#endif
|
||||
#undef F_HELPER
|
||||
|
||||
/* floating point conversion */
|
||||
float32 helper_fdtos(CPUSPARCState *env, float64 src)
|
||||
{
|
||||
return float64_to_float32(src, &env->fp_status);
|
||||
}
|
||||
|
||||
float64 helper_fstod(CPUSPARCState *env, float32 src)
|
||||
{
|
||||
return float32_to_float64(src, &env->fp_status);
|
||||
}
|
||||
|
||||
float32 helper_fqtos(CPUSPARCState *env)
|
||||
{
|
||||
return float128_to_float32(QT1, &env->fp_status);
|
||||
}
|
||||
|
||||
void helper_fstoq(CPUSPARCState *env, float32 src)
|
||||
{
|
||||
QT0 = float32_to_float128(src, &env->fp_status);
|
||||
}
|
||||
|
||||
float64 helper_fqtod(CPUSPARCState *env)
|
||||
{
|
||||
return float128_to_float64(QT1, &env->fp_status);
|
||||
}
|
||||
|
||||
void helper_fdtoq(CPUSPARCState *env, float64 src)
|
||||
{
|
||||
QT0 = float64_to_float128(src, &env->fp_status);
|
||||
}
|
||||
|
||||
/* Float to integer conversion. */
|
||||
int32_t helper_fstoi(CPUSPARCState *env, float32 src)
|
||||
{
|
||||
return float32_to_int32_round_to_zero(src, &env->fp_status);
|
||||
}
|
||||
|
||||
int32_t helper_fdtoi(CPUSPARCState *env, float64 src)
|
||||
{
|
||||
return float64_to_int32_round_to_zero(src, &env->fp_status);
|
||||
}
|
||||
|
||||
int32_t helper_fqtoi(CPUSPARCState *env)
|
||||
{
|
||||
return float128_to_int32_round_to_zero(QT1, &env->fp_status);
|
||||
}
|
||||
|
||||
#ifdef TARGET_SPARC64
|
||||
int64_t helper_fstox(CPUSPARCState *env, float32 src)
|
||||
{
|
||||
return float32_to_int64_round_to_zero(src, &env->fp_status);
|
||||
}
|
||||
|
||||
int64_t helper_fdtox(CPUSPARCState *env, float64 src)
|
||||
{
|
||||
return float64_to_int64_round_to_zero(src, &env->fp_status);
|
||||
}
|
||||
|
||||
int64_t helper_fqtox(CPUSPARCState *env)
|
||||
{
|
||||
return float128_to_int64_round_to_zero(QT1, &env->fp_status);
|
||||
}
|
||||
#endif
|
||||
|
||||
float32 helper_fabss(float32 src)
|
||||
{
|
||||
return float32_abs(src);
|
||||
}
|
||||
|
||||
#ifdef TARGET_SPARC64
|
||||
float64 helper_fabsd(float64 src)
|
||||
{
|
||||
return float64_abs(src);
|
||||
}
|
||||
|
||||
void helper_fabsq(CPUSPARCState *env)
|
||||
{
|
||||
QT0 = float128_abs(QT1);
|
||||
}
|
||||
#endif
|
||||
|
||||
float32 helper_fsqrts(CPUSPARCState *env, float32 src)
|
||||
{
|
||||
return float32_sqrt(src, &env->fp_status);
|
||||
}
|
||||
|
||||
float64 helper_fsqrtd(CPUSPARCState *env, float64 src)
|
||||
{
|
||||
return float64_sqrt(src, &env->fp_status);
|
||||
}
|
||||
|
||||
void helper_fsqrtq(CPUSPARCState *env)
|
||||
{
|
||||
QT0 = float128_sqrt(QT1, &env->fp_status);
|
||||
}
|
||||
|
||||
#define GEN_FCMP(name, size, reg1, reg2, FS, E) \
|
||||
target_ulong glue(helper_, name) (CPUSPARCState *env) \
|
||||
{ \
|
||||
int ret; \
|
||||
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); \
|
||||
} \
|
||||
fsr = do_check_ieee_exceptions(env, GETPC()); \
|
||||
switch (ret) { \
|
||||
case float_relation_unordered: \
|
||||
fsr |= (FSR_FCC1 | FSR_FCC0) << FS; \
|
||||
fsr |= FSR_NVA; \
|
||||
break; \
|
||||
case float_relation_less: \
|
||||
fsr &= ~(FSR_FCC1) << FS; \
|
||||
fsr |= FSR_FCC0 << FS; \
|
||||
break; \
|
||||
case float_relation_greater: \
|
||||
fsr &= ~(FSR_FCC0) << FS; \
|
||||
fsr |= FSR_FCC1 << FS; \
|
||||
break; \
|
||||
default: \
|
||||
fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \
|
||||
break; \
|
||||
} \
|
||||
return fsr; \
|
||||
}
|
||||
#define GEN_FCMP_T(name, size, FS, E) \
|
||||
target_ulong glue(helper_, name)(CPUSPARCState *env, size src1, size src2)\
|
||||
{ \
|
||||
int ret; \
|
||||
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); \
|
||||
} \
|
||||
fsr = do_check_ieee_exceptions(env, GETPC()); \
|
||||
switch (ret) { \
|
||||
case float_relation_unordered: \
|
||||
fsr |= (FSR_FCC1 | FSR_FCC0) << FS; \
|
||||
break; \
|
||||
case float_relation_less: \
|
||||
fsr &= ~(FSR_FCC1 << FS); \
|
||||
fsr |= FSR_FCC0 << FS; \
|
||||
break; \
|
||||
case float_relation_greater: \
|
||||
fsr &= ~(FSR_FCC0 << FS); \
|
||||
fsr |= FSR_FCC1 << FS; \
|
||||
break; \
|
||||
default: \
|
||||
fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \
|
||||
break; \
|
||||
} \
|
||||
return fsr; \
|
||||
}
|
||||
|
||||
GEN_FCMP_T(fcmps, float32, 0, 0);
|
||||
GEN_FCMP_T(fcmpd, float64, 0, 0);
|
||||
|
||||
GEN_FCMP_T(fcmpes, float32, 0, 1);
|
||||
GEN_FCMP_T(fcmped, float64, 0, 1);
|
||||
|
||||
GEN_FCMP(fcmpq, float128, QT0, QT1, 0, 0);
|
||||
GEN_FCMP(fcmpeq, float128, QT0, QT1, 0, 1);
|
||||
|
||||
#ifdef TARGET_SPARC64
|
||||
GEN_FCMP_T(fcmps_fcc1, float32, 22, 0);
|
||||
GEN_FCMP_T(fcmpd_fcc1, float64, 22, 0);
|
||||
GEN_FCMP(fcmpq_fcc1, float128, QT0, QT1, 22, 0);
|
||||
|
||||
GEN_FCMP_T(fcmps_fcc2, float32, 24, 0);
|
||||
GEN_FCMP_T(fcmpd_fcc2, float64, 24, 0);
|
||||
GEN_FCMP(fcmpq_fcc2, float128, QT0, QT1, 24, 0);
|
||||
|
||||
GEN_FCMP_T(fcmps_fcc3, float32, 26, 0);
|
||||
GEN_FCMP_T(fcmpd_fcc3, float64, 26, 0);
|
||||
GEN_FCMP(fcmpq_fcc3, float128, QT0, QT1, 26, 0);
|
||||
|
||||
GEN_FCMP_T(fcmpes_fcc1, float32, 22, 1);
|
||||
GEN_FCMP_T(fcmped_fcc1, float64, 22, 1);
|
||||
GEN_FCMP(fcmpeq_fcc1, float128, QT0, QT1, 22, 1);
|
||||
|
||||
GEN_FCMP_T(fcmpes_fcc2, float32, 24, 1);
|
||||
GEN_FCMP_T(fcmped_fcc2, float64, 24, 1);
|
||||
GEN_FCMP(fcmpeq_fcc2, float128, QT0, QT1, 24, 1);
|
||||
|
||||
GEN_FCMP_T(fcmpes_fcc3, float32, 26, 1);
|
||||
GEN_FCMP_T(fcmped_fcc3, float64, 26, 1);
|
||||
GEN_FCMP(fcmpeq_fcc3, float128, QT0, QT1, 26, 1);
|
||||
#endif
|
||||
#undef GEN_FCMP_T
|
||||
#undef GEN_FCMP
|
||||
|
||||
static void set_fsr(CPUSPARCState *env, target_ulong fsr)
|
||||
{
|
||||
int rnd_mode;
|
||||
|
||||
switch (fsr & FSR_RD_MASK) {
|
||||
case FSR_RD_NEAREST:
|
||||
rnd_mode = float_round_nearest_even;
|
||||
break;
|
||||
default:
|
||||
case FSR_RD_ZERO:
|
||||
rnd_mode = float_round_to_zero;
|
||||
break;
|
||||
case FSR_RD_POS:
|
||||
rnd_mode = float_round_up;
|
||||
break;
|
||||
case FSR_RD_NEG:
|
||||
rnd_mode = float_round_down;
|
||||
break;
|
||||
}
|
||||
set_float_rounding_mode(rnd_mode, &env->fp_status);
|
||||
}
|
||||
|
||||
target_ulong helper_ldfsr(CPUSPARCState *env, target_ulong old_fsr,
|
||||
uint32_t new_fsr)
|
||||
{
|
||||
old_fsr = (new_fsr & FSR_LDFSR_MASK) | (old_fsr & FSR_LDFSR_OLDMASK);
|
||||
set_fsr(env, old_fsr);
|
||||
return old_fsr;
|
||||
}
|
||||
|
||||
#ifdef TARGET_SPARC64
|
||||
target_ulong helper_ldxfsr(CPUSPARCState *env, target_ulong old_fsr,
|
||||
uint64_t new_fsr)
|
||||
{
|
||||
old_fsr = (new_fsr & FSR_LDXFSR_MASK) | (old_fsr & FSR_LDXFSR_OLDMASK);
|
||||
set_fsr(env, old_fsr);
|
||||
return old_fsr;
|
||||
}
|
||||
#endif
|
||||
247
qemu/target/sparc/helper.c
Normal file
247
qemu/target/sparc/helper.c
Normal file
@@ -0,0 +1,247 @@
|
||||
/*
|
||||
* Misc Sparc helpers
|
||||
*
|
||||
* Copyright (c) 2003-2005 Fabrice Bellard
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "cpu.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "qemu/host-utils.h"
|
||||
#include "exec/helper-proto.h"
|
||||
|
||||
void cpu_raise_exception_ra(CPUSPARCState *env, int tt, uintptr_t ra)
|
||||
{
|
||||
CPUState *cs = env_cpu(env);
|
||||
|
||||
cs->exception_index = tt;
|
||||
cpu_loop_exit_restore(cs, ra);
|
||||
}
|
||||
|
||||
void helper_raise_exception(CPUSPARCState *env, int tt)
|
||||
{
|
||||
CPUState *cs = env_cpu(env);
|
||||
|
||||
cs->exception_index = tt;
|
||||
cpu_loop_exit(cs);
|
||||
}
|
||||
|
||||
void helper_debug(CPUSPARCState *env)
|
||||
{
|
||||
CPUState *cs = env_cpu(env);
|
||||
|
||||
cs->exception_index = EXCP_DEBUG;
|
||||
cpu_loop_exit(cs);
|
||||
}
|
||||
|
||||
#ifdef TARGET_SPARC64
|
||||
void helper_tick_set_count(void *opaque, uint64_t count)
|
||||
{
|
||||
// cpu_tick_set_count(opaque, count);
|
||||
}
|
||||
|
||||
uint64_t helper_tick_get_count(CPUSPARCState *env, void *opaque, int mem_idx)
|
||||
{
|
||||
return 0;
|
||||
|
||||
#if 0
|
||||
CPUTimer *timer = opaque;
|
||||
|
||||
if (timer->npt && mem_idx < MMU_KERNEL_IDX) {
|
||||
cpu_raise_exception_ra(env, TT_PRIV_INSN, GETPC());
|
||||
}
|
||||
|
||||
return cpu_tick_get_count(timer);
|
||||
#endif
|
||||
}
|
||||
|
||||
void helper_tick_set_limit(void *opaque, uint64_t limit)
|
||||
{
|
||||
// cpu_tick_set_limit(opaque, limit);
|
||||
}
|
||||
#endif
|
||||
|
||||
static target_ulong do_udiv(CPUSPARCState *env, target_ulong a,
|
||||
target_ulong b, int cc, uintptr_t ra)
|
||||
{
|
||||
int overflow = 0;
|
||||
uint64_t x0;
|
||||
uint32_t x1;
|
||||
|
||||
x0 = (a & 0xffffffff) | ((int64_t) (env->y) << 32);
|
||||
x1 = (b & 0xffffffff);
|
||||
|
||||
if (x1 == 0) {
|
||||
cpu_raise_exception_ra(env, TT_DIV_ZERO, ra);
|
||||
}
|
||||
|
||||
x0 = x0 / x1;
|
||||
if (x0 > UINT32_MAX) {
|
||||
x0 = UINT32_MAX;
|
||||
overflow = 1;
|
||||
}
|
||||
|
||||
if (cc) {
|
||||
env->cc_dst = x0;
|
||||
env->cc_src2 = overflow;
|
||||
env->cc_op = CC_OP_DIV;
|
||||
}
|
||||
return x0;
|
||||
}
|
||||
|
||||
target_ulong helper_udiv(CPUSPARCState *env, target_ulong a, target_ulong b)
|
||||
{
|
||||
return do_udiv(env, a, b, 0, GETPC());
|
||||
}
|
||||
|
||||
target_ulong helper_udiv_cc(CPUSPARCState *env, target_ulong a, target_ulong b)
|
||||
{
|
||||
return do_udiv(env, a, b, 1, GETPC());
|
||||
}
|
||||
|
||||
static target_ulong do_sdiv(CPUSPARCState *env, target_ulong a,
|
||||
target_ulong b, int cc, uintptr_t ra)
|
||||
{
|
||||
int overflow = 0;
|
||||
int64_t x0;
|
||||
int32_t x1;
|
||||
|
||||
x0 = (a & 0xffffffff) | ((int64_t) (env->y) << 32);
|
||||
x1 = (b & 0xffffffff);
|
||||
|
||||
if (x1 == 0) {
|
||||
cpu_raise_exception_ra(env, TT_DIV_ZERO, ra);
|
||||
} else if (x1 == -1 && x0 == INT64_MIN) {
|
||||
x0 = INT32_MAX;
|
||||
overflow = 1;
|
||||
} else {
|
||||
x0 = x0 / x1;
|
||||
if ((int32_t) x0 != x0) {
|
||||
x0 = x0 < 0 ? INT32_MIN : INT32_MAX;
|
||||
overflow = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (cc) {
|
||||
env->cc_dst = x0;
|
||||
env->cc_src2 = overflow;
|
||||
env->cc_op = CC_OP_DIV;
|
||||
}
|
||||
return x0;
|
||||
}
|
||||
|
||||
target_ulong helper_sdiv(CPUSPARCState *env, target_ulong a, target_ulong b)
|
||||
{
|
||||
return do_sdiv(env, a, b, 0, GETPC());
|
||||
}
|
||||
|
||||
target_ulong helper_sdiv_cc(CPUSPARCState *env, target_ulong a, target_ulong b)
|
||||
{
|
||||
return do_sdiv(env, a, b, 1, GETPC());
|
||||
}
|
||||
|
||||
#ifdef TARGET_SPARC64
|
||||
int64_t helper_sdivx(CPUSPARCState *env, int64_t a, int64_t b)
|
||||
{
|
||||
if (b == 0) {
|
||||
/* Raise divide by zero trap. */
|
||||
cpu_raise_exception_ra(env, TT_DIV_ZERO, GETPC());
|
||||
} else if (b == -1) {
|
||||
/* Avoid overflow trap with i386 divide insn. */
|
||||
return -a;
|
||||
} else {
|
||||
return a / b;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t helper_udivx(CPUSPARCState *env, uint64_t a, uint64_t b)
|
||||
{
|
||||
if (b == 0) {
|
||||
/* Raise divide by zero trap. */
|
||||
cpu_raise_exception_ra(env, TT_DIV_ZERO, GETPC());
|
||||
}
|
||||
return a / b;
|
||||
}
|
||||
#endif
|
||||
|
||||
target_ulong helper_taddcctv(CPUSPARCState *env, target_ulong src1,
|
||||
target_ulong src2)
|
||||
{
|
||||
target_ulong dst;
|
||||
|
||||
/* Tag overflow occurs if either input has bits 0 or 1 set. */
|
||||
if ((src1 | src2) & 3) {
|
||||
goto tag_overflow;
|
||||
}
|
||||
|
||||
dst = src1 + src2;
|
||||
|
||||
/* Tag overflow occurs if the addition overflows. */
|
||||
if (~(src1 ^ src2) & (src1 ^ dst) & (1u << 31)) {
|
||||
goto tag_overflow;
|
||||
}
|
||||
|
||||
/* Only modify the CC after any exceptions have been generated. */
|
||||
env->cc_op = CC_OP_TADDTV;
|
||||
env->cc_src = src1;
|
||||
env->cc_src2 = src2;
|
||||
env->cc_dst = dst;
|
||||
return dst;
|
||||
|
||||
tag_overflow:
|
||||
cpu_raise_exception_ra(env, TT_TOVF, GETPC());
|
||||
}
|
||||
|
||||
target_ulong helper_tsubcctv(CPUSPARCState *env, target_ulong src1,
|
||||
target_ulong src2)
|
||||
{
|
||||
target_ulong dst;
|
||||
|
||||
/* Tag overflow occurs if either input has bits 0 or 1 set. */
|
||||
if ((src1 | src2) & 3) {
|
||||
goto tag_overflow;
|
||||
}
|
||||
|
||||
dst = src1 - src2;
|
||||
|
||||
/* Tag overflow occurs if the subtraction overflows. */
|
||||
if ((src1 ^ src2) & (src1 ^ dst) & (1u << 31)) {
|
||||
goto tag_overflow;
|
||||
}
|
||||
|
||||
/* Only modify the CC after any exceptions have been generated. */
|
||||
env->cc_op = CC_OP_TSUBTV;
|
||||
env->cc_src = src1;
|
||||
env->cc_src2 = src2;
|
||||
env->cc_dst = dst;
|
||||
return dst;
|
||||
|
||||
tag_overflow:
|
||||
cpu_raise_exception_ra(env, TT_TOVF, GETPC());
|
||||
}
|
||||
|
||||
#ifndef TARGET_SPARC64
|
||||
void helper_power_down(CPUSPARCState *env)
|
||||
{
|
||||
CPUState *cs = env_cpu(env);
|
||||
|
||||
cs->halted = 1;
|
||||
cs->exception_index = EXCP_HLT;
|
||||
env->pc = env->npc;
|
||||
env->npc = env->pc + 4;
|
||||
cpu_loop_exit(cs);
|
||||
}
|
||||
#endif
|
||||
168
qemu/target/sparc/helper.h
Normal file
168
qemu/target/sparc/helper.h
Normal file
@@ -0,0 +1,168 @@
|
||||
DEF_HELPER_4(uc_tracecode, void, i32, i32, ptr, i64)
|
||||
|
||||
#ifndef TARGET_SPARC64
|
||||
DEF_HELPER_1(rett, void, env)
|
||||
DEF_HELPER_2(wrpsr, void, env, tl)
|
||||
DEF_HELPER_1(rdpsr, tl, env)
|
||||
DEF_HELPER_1(power_down, void, env)
|
||||
#else
|
||||
DEF_HELPER_FLAGS_2(wrpil, TCG_CALL_NO_RWG, void, env, tl)
|
||||
DEF_HELPER_2(wrgl, void, env, tl)
|
||||
DEF_HELPER_2(wrpstate, void, env, tl)
|
||||
DEF_HELPER_1(done, void, env)
|
||||
DEF_HELPER_1(retry, 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_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
|
||||
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)
|
||||
DEF_HELPER_3(udiv, tl, env, tl, tl)
|
||||
DEF_HELPER_3(udiv_cc, tl, env, tl, tl)
|
||||
DEF_HELPER_3(sdiv, tl, env, tl, tl)
|
||||
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_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_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)
|
||||
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_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_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_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_FLAGS_1(f ## name, TCG_CALL_NO_RWG, void, env)
|
||||
|
||||
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_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_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_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_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_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_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_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)
|
||||
DEF_HELPER_FLAGS_2(fmul8x16al, TCG_CALL_NO_RWG_SE, i64, i64, i64)
|
||||
DEF_HELPER_FLAGS_2(fmul8x16au, TCG_CALL_NO_RWG_SE, i64, i64, i64)
|
||||
DEF_HELPER_FLAGS_2(fmul8sux16, TCG_CALL_NO_RWG_SE, i64, i64, i64)
|
||||
DEF_HELPER_FLAGS_2(fmul8ulx16, TCG_CALL_NO_RWG_SE, i64, i64, i64)
|
||||
DEF_HELPER_FLAGS_2(fmuld8sux16, TCG_CALL_NO_RWG_SE, i64, i64, i64)
|
||||
DEF_HELPER_FLAGS_2(fmuld8ulx16, TCG_CALL_NO_RWG_SE, i64, i64, i64)
|
||||
DEF_HELPER_FLAGS_2(fexpand, TCG_CALL_NO_RWG_SE, i64, i64, i64)
|
||||
DEF_HELPER_FLAGS_3(pdist, TCG_CALL_NO_RWG_SE, i64, i64, i64, i64)
|
||||
DEF_HELPER_FLAGS_2(fpack16, TCG_CALL_NO_RWG_SE, i32, i64, i64)
|
||||
DEF_HELPER_FLAGS_3(fpack32, TCG_CALL_NO_RWG_SE, i64, i64, i64, i64)
|
||||
DEF_HELPER_FLAGS_2(fpackfix, TCG_CALL_NO_RWG_SE, i32, i64, i64)
|
||||
DEF_HELPER_FLAGS_3(bshuffle, TCG_CALL_NO_RWG_SE, i64, i64, i64, i64)
|
||||
#define VIS_HELPER(name) \
|
||||
DEF_HELPER_FLAGS_2(f ## name ## 16, TCG_CALL_NO_RWG_SE, \
|
||||
i64, i64, i64) \
|
||||
DEF_HELPER_FLAGS_2(f ## name ## 16s, TCG_CALL_NO_RWG_SE, \
|
||||
i32, i32, i32) \
|
||||
DEF_HELPER_FLAGS_2(f ## name ## 32, TCG_CALL_NO_RWG_SE, \
|
||||
i64, i64, i64) \
|
||||
DEF_HELPER_FLAGS_2(f ## name ## 32s, TCG_CALL_NO_RWG_SE, \
|
||||
i32, i32, i32)
|
||||
|
||||
VIS_HELPER(padd)
|
||||
VIS_HELPER(psub)
|
||||
#define VIS_CMPHELPER(name) \
|
||||
DEF_HELPER_FLAGS_2(f##name##16, TCG_CALL_NO_RWG_SE, \
|
||||
i64, i64, i64) \
|
||||
DEF_HELPER_FLAGS_2(f##name##32, TCG_CALL_NO_RWG_SE, \
|
||||
i64, i64, i64)
|
||||
VIS_CMPHELPER(cmpgt)
|
||||
VIS_CMPHELPER(cmpeq)
|
||||
VIS_CMPHELPER(cmple)
|
||||
VIS_CMPHELPER(cmpne)
|
||||
#endif
|
||||
#undef F_HELPER_0_1
|
||||
#undef VIS_HELPER
|
||||
#undef VIS_CMPHELPER
|
||||
DEF_HELPER_1(compute_psr, void, env)
|
||||
DEF_HELPER_FLAGS_1(compute_C_icc, TCG_CALL_NO_WG_SE, i32, env)
|
||||
95
qemu/target/sparc/int32_helper.c
Normal file
95
qemu/target/sparc/int32_helper.c
Normal file
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Sparc32 interrupt helpers
|
||||
*
|
||||
* Copyright (c) 2003-2005 Fabrice Bellard
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "cpu.h"
|
||||
//#include "sysemu/runstate.h"
|
||||
|
||||
|
||||
void sparc_cpu_do_interrupt(CPUState *cs)
|
||||
{
|
||||
SPARCCPU *cpu = SPARC_CPU(cs);
|
||||
CPUSPARCState *env = &cpu->env;
|
||||
int cwp, intno = cs->exception_index;
|
||||
|
||||
/* Compute PSR before exposing state. */
|
||||
if (env->cc_op != CC_OP_FLAGS) {
|
||||
cpu_get_psr(env);
|
||||
}
|
||||
|
||||
if (env->psret == 0) {
|
||||
if (cs->exception_index == 0x80 &&
|
||||
env->def.features & CPU_FEATURE_TA0_SHUTDOWN) {
|
||||
// qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
|
||||
} else {
|
||||
cpu_abort(cs, "Trap 0x%02x while interrupts disabled, Error state",
|
||||
cs->exception_index);
|
||||
}
|
||||
return;
|
||||
}
|
||||
env->psret = 0;
|
||||
cwp = cpu_cwp_dec(env, env->cwp - 1);
|
||||
cpu_set_cwp(env, cwp);
|
||||
env->regwptr[9] = env->pc;
|
||||
env->regwptr[10] = env->npc;
|
||||
env->psrps = env->psrs;
|
||||
env->psrs = 1;
|
||||
env->tbr = (env->tbr & TBR_BASE_MASK) | (intno << 4);
|
||||
env->pc = env->tbr;
|
||||
env->npc = env->pc + 4;
|
||||
cs->exception_index = -1;
|
||||
|
||||
/* IRQ acknowledgment */
|
||||
if ((intno & ~15) == TT_EXTINT && env->qemu_irq_ack != NULL) {
|
||||
env->qemu_irq_ack(env, env->irq_manager, intno);
|
||||
}
|
||||
}
|
||||
|
||||
static void leon3_cache_control_int(CPUSPARCState *env)
|
||||
{
|
||||
uint32_t state = 0;
|
||||
|
||||
if (env->cache_control & CACHE_CTRL_IF) {
|
||||
/* Instruction cache state */
|
||||
state = env->cache_control & CACHE_STATE_MASK;
|
||||
if (state == CACHE_ENABLED) {
|
||||
state = CACHE_FROZEN;
|
||||
}
|
||||
|
||||
env->cache_control &= ~CACHE_STATE_MASK;
|
||||
env->cache_control |= state;
|
||||
}
|
||||
|
||||
if (env->cache_control & CACHE_CTRL_DF) {
|
||||
/* Data cache state */
|
||||
state = (env->cache_control >> 2) & CACHE_STATE_MASK;
|
||||
if (state == CACHE_ENABLED) {
|
||||
state = CACHE_FROZEN;
|
||||
}
|
||||
|
||||
env->cache_control &= ~(CACHE_STATE_MASK << 2);
|
||||
env->cache_control |= (state << 2);
|
||||
}
|
||||
}
|
||||
|
||||
void leon3_irq_manager(CPUSPARCState *env, void *irq_manager, int intno)
|
||||
{
|
||||
// leon3_irq_ack(irq_manager, intno);
|
||||
leon3_cache_control_int(env);
|
||||
}
|
||||
174
qemu/target/sparc/int64_helper.c
Normal file
174
qemu/target/sparc/int64_helper.c
Normal file
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
* Sparc64 interrupt helpers
|
||||
*
|
||||
* Copyright (c) 2003-2005 Fabrice Bellard
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "cpu.h"
|
||||
#include "exec/helper-proto.h"
|
||||
|
||||
void sparc_cpu_do_interrupt(CPUState *cs)
|
||||
{
|
||||
SPARCCPU *cpu = SPARC_CPU(cs);
|
||||
CPUSPARCState *env = &cpu->env;
|
||||
int intno = cs->exception_index;
|
||||
trap_state *tsptr;
|
||||
|
||||
/* Compute PSR before exposing state. */
|
||||
if (env->cc_op != CC_OP_FLAGS) {
|
||||
cpu_get_psr(env);
|
||||
}
|
||||
|
||||
if (env->tl >= env->maxtl) {
|
||||
cpu_abort(cs, "Trap 0x%04x while trap level (%d) >= MAXTL (%d),"
|
||||
" Error state", cs->exception_index, env->tl, env->maxtl);
|
||||
return;
|
||||
}
|
||||
if (env->tl < env->maxtl - 1) {
|
||||
env->tl++;
|
||||
} else {
|
||||
env->pstate |= PS_RED;
|
||||
if (env->tl < env->maxtl) {
|
||||
env->tl++;
|
||||
}
|
||||
}
|
||||
tsptr = cpu_tsptr(env);
|
||||
|
||||
tsptr->tstate = (cpu_get_ccr(env) << 32) |
|
||||
((env->asi & 0xff) << 24) | ((env->pstate & 0xf3f) << 8) |
|
||||
cpu_get_cwp64(env);
|
||||
tsptr->tpc = env->pc;
|
||||
tsptr->tnpc = env->npc;
|
||||
tsptr->tt = intno;
|
||||
|
||||
if (cpu_has_hypervisor(env)) {
|
||||
env->htstate[env->tl] = env->hpstate;
|
||||
/* XXX OpenSPARC T1 - UltraSPARC T3 have MAXPTL=2
|
||||
but this may change in the future */
|
||||
if (env->tl > 2) {
|
||||
env->hpstate |= HS_PRIV;
|
||||
}
|
||||
}
|
||||
|
||||
if (env->def.features & CPU_FEATURE_GL) {
|
||||
tsptr->tstate |= (env->gl & 7ULL) << 40;
|
||||
cpu_gl_switch_gregs(env, env->gl + 1);
|
||||
env->gl++;
|
||||
}
|
||||
|
||||
switch (intno) {
|
||||
case TT_IVEC:
|
||||
if (!cpu_has_hypervisor(env)) {
|
||||
cpu_change_pstate(env, PS_PEF | PS_PRIV | PS_IG);
|
||||
}
|
||||
break;
|
||||
case TT_TFAULT:
|
||||
case TT_DFAULT:
|
||||
case TT_TMISS:
|
||||
case TT_TMISS + 1:
|
||||
case TT_TMISS + 2:
|
||||
case TT_TMISS + 3:
|
||||
|
||||
case TT_DMISS:
|
||||
case TT_DMISS + 1:
|
||||
case TT_DMISS + 2:
|
||||
case TT_DMISS + 3:
|
||||
|
||||
case TT_DPROT:
|
||||
case TT_DPROT + 1:
|
||||
case TT_DPROT + 2:
|
||||
case TT_DPROT + 3:
|
||||
|
||||
if (cpu_has_hypervisor(env)) {
|
||||
env->hpstate |= HS_PRIV;
|
||||
env->pstate = PS_PEF | PS_PRIV;
|
||||
} else {
|
||||
cpu_change_pstate(env, PS_PEF | PS_PRIV | PS_MG);
|
||||
}
|
||||
break;
|
||||
// case TT_INSN_REAL_TRANSLATION_MISS ... TT_DATA_REAL_TRANSLATION_MISS:
|
||||
// case TT_HTRAP ... TT_HTRAP + 127:
|
||||
// env->hpstate |= HS_PRIV;
|
||||
// break;
|
||||
default:
|
||||
if (intno >= TT_INSN_REAL_TRANSLATION_MISS && intno <= TT_DATA_REAL_TRANSLATION_MISS) {
|
||||
env->hpstate |= HS_PRIV;
|
||||
break;
|
||||
}
|
||||
if (intno >= TT_HTRAP && intno <= TT_HTRAP + 127) {
|
||||
env->hpstate |= HS_PRIV;
|
||||
break;
|
||||
}
|
||||
cpu_change_pstate(env, PS_PEF | PS_PRIV | PS_AG);
|
||||
break;
|
||||
}
|
||||
|
||||
if (intno == TT_CLRWIN) {
|
||||
cpu_set_cwp(env, cpu_cwp_dec(env, env->cwp - 1));
|
||||
} else if ((intno & 0x1c0) == TT_SPILL) {
|
||||
cpu_set_cwp(env, cpu_cwp_dec(env, env->cwp - env->cansave - 2));
|
||||
} else if ((intno & 0x1c0) == TT_FILL) {
|
||||
cpu_set_cwp(env, cpu_cwp_inc(env, env->cwp + 1));
|
||||
}
|
||||
|
||||
if (cpu_hypervisor_mode(env)) {
|
||||
env->pc = (env->htba & ~0x3fffULL) | (intno << 5);
|
||||
} else {
|
||||
env->pc = env->tbr & ~0x7fffULL;
|
||||
env->pc |= ((env->tl > 1) ? 1 << 14 : 0) | (intno << 5);
|
||||
}
|
||||
env->npc = env->pc + 4;
|
||||
cs->exception_index = -1;
|
||||
}
|
||||
|
||||
trap_state *cpu_tsptr(CPUSPARCState* env)
|
||||
{
|
||||
return &env->ts[env->tl & MAXTL_MASK];
|
||||
}
|
||||
|
||||
static bool do_modify_softint(CPUSPARCState *env, uint32_t value)
|
||||
{
|
||||
if (env->softint != value) {
|
||||
env->softint = value;
|
||||
if (cpu_interrupts_enabled(env)) {
|
||||
// cpu_check_irqs(env);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void helper_set_softint(CPUSPARCState *env, uint64_t value)
|
||||
{
|
||||
if (do_modify_softint(env, env->softint | (uint32_t)value)) {
|
||||
// trace_int_helper_set_softint(env->softint);
|
||||
}
|
||||
}
|
||||
|
||||
void helper_clear_softint(CPUSPARCState *env, uint64_t value)
|
||||
{
|
||||
if (do_modify_softint(env, env->softint & (uint32_t)~value)) {
|
||||
// trace_int_helper_clear_softint(env->softint);
|
||||
}
|
||||
}
|
||||
|
||||
void helper_write_softint(CPUSPARCState *env, uint64_t value)
|
||||
{
|
||||
if (do_modify_softint(env, (uint32_t)value)) {
|
||||
// trace_int_helper_write_softint(env->softint);
|
||||
}
|
||||
}
|
||||
1878
qemu/target/sparc/ldst_helper.c
Normal file
1878
qemu/target/sparc/ldst_helper.c
Normal file
File diff suppressed because it is too large
Load Diff
768
qemu/target/sparc/mmu_helper.c
Normal file
768
qemu/target/sparc/mmu_helper.c
Normal file
@@ -0,0 +1,768 @@
|
||||
/*
|
||||
* Sparc MMU helpers
|
||||
*
|
||||
* Copyright (c) 2003-2005 Fabrice Bellard
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "cpu.h"
|
||||
#include "exec/exec-all.h"
|
||||
|
||||
/* Sparc MMU emulation */
|
||||
|
||||
#ifndef TARGET_SPARC64
|
||||
/*
|
||||
* Sparc V8 Reference MMU (SRMMU)
|
||||
*/
|
||||
static const int access_table[8][8] = {
|
||||
{ 0, 0, 0, 0, 8, 0, 12, 12 },
|
||||
{ 0, 0, 0, 0, 8, 0, 0, 0 },
|
||||
{ 8, 8, 0, 0, 0, 8, 12, 12 },
|
||||
{ 8, 8, 0, 0, 0, 8, 0, 0 },
|
||||
{ 8, 0, 8, 0, 8, 8, 12, 12 },
|
||||
{ 8, 0, 8, 0, 8, 0, 8, 0 },
|
||||
{ 8, 8, 8, 0, 8, 8, 12, 12 },
|
||||
{ 8, 8, 8, 0, 8, 8, 8, 0 }
|
||||
};
|
||||
|
||||
static const int perm_table[2][8] = {
|
||||
{
|
||||
PAGE_READ,
|
||||
PAGE_READ | PAGE_WRITE,
|
||||
PAGE_READ | PAGE_EXEC,
|
||||
PAGE_READ | PAGE_WRITE | PAGE_EXEC,
|
||||
PAGE_EXEC,
|
||||
PAGE_READ | PAGE_WRITE,
|
||||
PAGE_READ | PAGE_EXEC,
|
||||
PAGE_READ | PAGE_WRITE | PAGE_EXEC
|
||||
},
|
||||
{
|
||||
PAGE_READ,
|
||||
PAGE_READ | PAGE_WRITE,
|
||||
PAGE_READ | PAGE_EXEC,
|
||||
PAGE_READ | PAGE_WRITE | PAGE_EXEC,
|
||||
PAGE_EXEC,
|
||||
PAGE_READ,
|
||||
0,
|
||||
0,
|
||||
}
|
||||
};
|
||||
|
||||
static int get_physical_address(CPUSPARCState *env, hwaddr *physical,
|
||||
int *prot, int *access_index, MemTxAttrs *attrs,
|
||||
target_ulong address, int rw, int mmu_idx,
|
||||
target_ulong *page_size)
|
||||
{
|
||||
int access_perms = 0;
|
||||
hwaddr pde_ptr;
|
||||
uint32_t pde;
|
||||
int error_code = 0, is_dirty, is_user;
|
||||
unsigned long page_offset;
|
||||
CPUState *cs = env_cpu(env);
|
||||
MemTxResult result;
|
||||
|
||||
is_user = mmu_idx == MMU_USER_IDX;
|
||||
|
||||
if (mmu_idx == MMU_PHYS_IDX) {
|
||||
*page_size = TARGET_PAGE_SIZE;
|
||||
/* Boot mode: instruction fetches are taken from PROM */
|
||||
if (rw == 2 && (env->mmuregs[0] & env->def.mmu_bm)) {
|
||||
*physical = env->prom_addr | (address & 0x7ffffULL);
|
||||
*prot = PAGE_READ | PAGE_EXEC;
|
||||
return 0;
|
||||
}
|
||||
*physical = address;
|
||||
*prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
|
||||
return 0;
|
||||
}
|
||||
|
||||
*access_index = ((rw & 1) << 2) | (rw & 2) | (is_user ? 0 : 1);
|
||||
*physical = 0xffffffffffff0000ULL;
|
||||
|
||||
/* SPARC reference MMU table walk: Context table->L1->L2->PTE */
|
||||
/* Context base + context number */
|
||||
pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2);
|
||||
pde = glue(address_space_ldl, UNICORN_ARCH_POSTFIX)(cs->as->uc, cs->as, pde_ptr, MEMTXATTRS_UNSPECIFIED, &result);
|
||||
if (result != MEMTX_OK) {
|
||||
return 4 << 2; /* Translation fault, L = 0 */
|
||||
}
|
||||
|
||||
/* Ctx pde */
|
||||
switch (pde & PTE_ENTRYTYPE_MASK) {
|
||||
default:
|
||||
case 0: /* Invalid */
|
||||
return 1 << 2;
|
||||
case 2: /* L0 PTE, maybe should not happen? */
|
||||
case 3: /* Reserved */
|
||||
return 4 << 2;
|
||||
case 1: /* L0 PDE */
|
||||
pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4);
|
||||
pde = glue(address_space_ldl, UNICORN_ARCH_POSTFIX)(cs->as->uc, cs->as, pde_ptr,
|
||||
MEMTXATTRS_UNSPECIFIED, &result);
|
||||
if (result != MEMTX_OK) {
|
||||
return (1 << 8) | (4 << 2); /* Translation fault, L = 1 */
|
||||
}
|
||||
|
||||
switch (pde & PTE_ENTRYTYPE_MASK) {
|
||||
default:
|
||||
case 0: /* Invalid */
|
||||
return (1 << 8) | (1 << 2);
|
||||
case 3: /* Reserved */
|
||||
return (1 << 8) | (4 << 2);
|
||||
case 1: /* L1 PDE */
|
||||
pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4);
|
||||
pde = glue(address_space_ldl, UNICORN_ARCH_POSTFIX)(cs->as->uc, cs->as, pde_ptr,
|
||||
MEMTXATTRS_UNSPECIFIED, &result);
|
||||
if (result != MEMTX_OK) {
|
||||
return (2 << 8) | (4 << 2); /* Translation fault, L = 2 */
|
||||
}
|
||||
|
||||
switch (pde & PTE_ENTRYTYPE_MASK) {
|
||||
default:
|
||||
case 0: /* Invalid */
|
||||
return (2 << 8) | (1 << 2);
|
||||
case 3: /* Reserved */
|
||||
return (2 << 8) | (4 << 2);
|
||||
case 1: /* L2 PDE */
|
||||
pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4);
|
||||
pde = glue(address_space_ldl, UNICORN_ARCH_POSTFIX)(cs->as->uc, cs->as, pde_ptr,
|
||||
MEMTXATTRS_UNSPECIFIED, &result);
|
||||
if (result != MEMTX_OK) {
|
||||
return (3 << 8) | (4 << 2); /* Translation fault, L = 3 */
|
||||
}
|
||||
|
||||
switch (pde & PTE_ENTRYTYPE_MASK) {
|
||||
default:
|
||||
case 0: /* Invalid */
|
||||
return (3 << 8) | (1 << 2);
|
||||
case 1: /* PDE, should not happen */
|
||||
case 3: /* Reserved */
|
||||
return (3 << 8) | (4 << 2);
|
||||
case 2: /* L3 PTE */
|
||||
page_offset = 0;
|
||||
}
|
||||
*page_size = TARGET_PAGE_SIZE;
|
||||
break;
|
||||
case 2: /* L2 PTE */
|
||||
page_offset = address & 0x3f000;
|
||||
*page_size = 0x40000;
|
||||
}
|
||||
break;
|
||||
case 2: /* L1 PTE */
|
||||
page_offset = address & 0xfff000;
|
||||
*page_size = 0x1000000;
|
||||
}
|
||||
}
|
||||
|
||||
/* check access */
|
||||
access_perms = (pde & PTE_ACCESS_MASK) >> PTE_ACCESS_SHIFT;
|
||||
error_code = access_table[*access_index][access_perms];
|
||||
if (error_code && !((env->mmuregs[0] & MMU_NF) && is_user)) {
|
||||
return error_code;
|
||||
}
|
||||
|
||||
/* update page modified and dirty bits */
|
||||
is_dirty = (rw & 1) && !(pde & PG_MODIFIED_MASK);
|
||||
if (!(pde & PG_ACCESSED_MASK) || is_dirty) {
|
||||
pde |= PG_ACCESSED_MASK;
|
||||
if (is_dirty) {
|
||||
pde |= PG_MODIFIED_MASK;
|
||||
}
|
||||
stl_phys_notdirty(cs->as, pde_ptr, pde);
|
||||
}
|
||||
|
||||
/* the page can be put in the TLB */
|
||||
*prot = perm_table[is_user][access_perms];
|
||||
if (!(pde & PG_MODIFIED_MASK)) {
|
||||
/* only set write access if already dirty... otherwise wait
|
||||
for dirty access */
|
||||
*prot &= ~PAGE_WRITE;
|
||||
}
|
||||
|
||||
/* Even if large ptes, we map only one 4KB page in the cache to
|
||||
avoid filling it too fast */
|
||||
*physical = ((hwaddr)(pde & PTE_ADDR_MASK) << 4) + page_offset;
|
||||
return error_code;
|
||||
}
|
||||
|
||||
/* Perform address translation */
|
||||
bool sparc_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
||||
MMUAccessType access_type, int mmu_idx,
|
||||
bool probe, uintptr_t retaddr)
|
||||
{
|
||||
SPARCCPU *cpu = SPARC_CPU(cs);
|
||||
CPUSPARCState *env = &cpu->env;
|
||||
hwaddr paddr;
|
||||
target_ulong vaddr;
|
||||
target_ulong page_size;
|
||||
int error_code = 0, prot, access_index;
|
||||
MemTxAttrs attrs = { 0 };
|
||||
|
||||
/*
|
||||
* TODO: If we ever need tlb_vaddr_to_host for this target,
|
||||
* then we must figure out how to manipulate FSR and FAR
|
||||
* when both MMU_NF and probe are set. In the meantime,
|
||||
* do not support this use case.
|
||||
*/
|
||||
assert(!probe);
|
||||
|
||||
address &= TARGET_PAGE_MASK;
|
||||
error_code = get_physical_address(env, &paddr, &prot, &access_index, &attrs,
|
||||
address, access_type,
|
||||
mmu_idx, &page_size);
|
||||
vaddr = address;
|
||||
if (likely(error_code == 0)) {
|
||||
qemu_log_mask(CPU_LOG_MMU,
|
||||
"Translate at %" VADDR_PRIx " -> "
|
||||
TARGET_FMT_plx ", vaddr " TARGET_FMT_lx "\n",
|
||||
address, paddr, vaddr);
|
||||
tlb_set_page(cs, vaddr, paddr, prot, mmu_idx, page_size);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (env->mmuregs[3]) { /* Fault status register */
|
||||
env->mmuregs[3] = 1; /* overflow (not read before another fault) */
|
||||
}
|
||||
env->mmuregs[3] |= (access_index << 5) | error_code | 2;
|
||||
env->mmuregs[4] = address; /* Fault address register */
|
||||
|
||||
if ((env->mmuregs[0] & MMU_NF) || env->psret == 0) {
|
||||
/* No fault mode: if a mapping is available, just override
|
||||
permissions. If no mapping is available, redirect accesses to
|
||||
neverland. Fake/overridden mappings will be flushed when
|
||||
switching to normal mode. */
|
||||
prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
|
||||
tlb_set_page(cs, vaddr, paddr, prot, mmu_idx, TARGET_PAGE_SIZE);
|
||||
return true;
|
||||
} else {
|
||||
if (access_type == MMU_INST_FETCH) {
|
||||
cs->exception_index = TT_TFAULT;
|
||||
} else {
|
||||
cs->exception_index = TT_DFAULT;
|
||||
}
|
||||
cpu_loop_exit_restore(cs, retaddr);
|
||||
}
|
||||
}
|
||||
|
||||
target_ulong mmu_probe(CPUSPARCState *env, target_ulong address, int mmulev)
|
||||
{
|
||||
CPUState *cs = env_cpu(env);
|
||||
hwaddr pde_ptr;
|
||||
uint32_t pde;
|
||||
MemTxResult result;
|
||||
|
||||
/*
|
||||
* TODO: MMU probe operations are supposed to set the fault
|
||||
* status registers, but we don't do this.
|
||||
*/
|
||||
|
||||
/* Context base + context number */
|
||||
pde_ptr = (hwaddr)(env->mmuregs[1] << 4) +
|
||||
(env->mmuregs[2] << 2);
|
||||
pde = glue(address_space_ldl, UNICORN_ARCH_POSTFIX)(cs->as->uc, cs->as, pde_ptr, MEMTXATTRS_UNSPECIFIED, &result);
|
||||
if (result != MEMTX_OK) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (pde & PTE_ENTRYTYPE_MASK) {
|
||||
default:
|
||||
case 0: /* Invalid */
|
||||
case 2: /* PTE, maybe should not happen? */
|
||||
case 3: /* Reserved */
|
||||
return 0;
|
||||
case 1: /* L1 PDE */
|
||||
if (mmulev == 3) {
|
||||
return pde;
|
||||
}
|
||||
pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4);
|
||||
pde = glue(address_space_ldl, UNICORN_ARCH_POSTFIX)(cs->as->uc, cs->as, pde_ptr,
|
||||
MEMTXATTRS_UNSPECIFIED, &result);
|
||||
if (result != MEMTX_OK) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (pde & PTE_ENTRYTYPE_MASK) {
|
||||
default:
|
||||
case 0: /* Invalid */
|
||||
case 3: /* Reserved */
|
||||
return 0;
|
||||
case 2: /* L1 PTE */
|
||||
return pde;
|
||||
case 1: /* L2 PDE */
|
||||
if (mmulev == 2) {
|
||||
return pde;
|
||||
}
|
||||
pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4);
|
||||
pde = glue(address_space_ldl, UNICORN_ARCH_POSTFIX)(cs->as->uc, cs->as, pde_ptr,
|
||||
MEMTXATTRS_UNSPECIFIED, &result);
|
||||
if (result != MEMTX_OK) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (pde & PTE_ENTRYTYPE_MASK) {
|
||||
default:
|
||||
case 0: /* Invalid */
|
||||
case 3: /* Reserved */
|
||||
return 0;
|
||||
case 2: /* L2 PTE */
|
||||
return pde;
|
||||
case 1: /* L3 PDE */
|
||||
if (mmulev == 1) {
|
||||
return pde;
|
||||
}
|
||||
pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4);
|
||||
pde = glue(address_space_ldl, UNICORN_ARCH_POSTFIX)(cs->as->uc, cs->as, pde_ptr,
|
||||
MEMTXATTRS_UNSPECIFIED, &result);
|
||||
if (result != MEMTX_OK) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (pde & PTE_ENTRYTYPE_MASK) {
|
||||
default:
|
||||
case 0: /* Invalid */
|
||||
case 1: /* PDE, should not happen */
|
||||
case 3: /* Reserved */
|
||||
return 0;
|
||||
case 2: /* L3 PTE */
|
||||
return pde;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Gdb expects all registers windows to be flushed in ram. This function handles
|
||||
* reads (and only reads) in stack frames as if windows were flushed. We assume
|
||||
* that the sparc ABI is followed.
|
||||
*/
|
||||
int sparc_cpu_memory_rw_debug(CPUState *cs, vaddr address,
|
||||
uint8_t *buf, int len, bool is_write)
|
||||
{
|
||||
SPARCCPU *cpu = SPARC_CPU(cs);
|
||||
CPUSPARCState *env = &cpu->env;
|
||||
target_ulong addr = address;
|
||||
int i;
|
||||
int len1;
|
||||
int cwp = env->cwp;
|
||||
|
||||
if (!is_write) {
|
||||
for (i = 0; i < env->nwindows; i++) {
|
||||
int off;
|
||||
target_ulong fp = env->regbase[cwp * 16 + 22];
|
||||
|
||||
/* Assume fp == 0 means end of frame. */
|
||||
if (fp == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
cwp = cpu_cwp_inc(env, cwp + 1);
|
||||
|
||||
/* Invalid window ? */
|
||||
if (env->wim & (1 << cwp)) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* According to the ABI, the stack is growing downward. */
|
||||
if (addr + len < fp) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Not in this frame. */
|
||||
if (addr > fp + 64) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Handle access before this window. */
|
||||
if (addr < fp) {
|
||||
len1 = fp - addr;
|
||||
if (cpu_memory_rw_debug(cs, addr, buf, len1, is_write) != 0) {
|
||||
return -1;
|
||||
}
|
||||
addr += len1;
|
||||
len -= len1;
|
||||
buf += len1;
|
||||
}
|
||||
|
||||
/* Access byte per byte to registers. Not very efficient but speed
|
||||
* is not critical.
|
||||
*/
|
||||
off = addr - fp;
|
||||
len1 = 64 - off;
|
||||
|
||||
if (len1 > len) {
|
||||
len1 = len;
|
||||
}
|
||||
|
||||
for (; len1; len1--) {
|
||||
int reg = cwp * 16 + 8 + (off >> 2);
|
||||
union {
|
||||
uint32_t v;
|
||||
uint8_t c[4];
|
||||
} u;
|
||||
u.v = cpu_to_be32(env->regbase[reg]);
|
||||
*buf++ = u.c[off & 3];
|
||||
addr++;
|
||||
len--;
|
||||
off++;
|
||||
}
|
||||
|
||||
if (len == 0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return cpu_memory_rw_debug(cs, addr, buf, len, is_write);
|
||||
}
|
||||
|
||||
#else /* !TARGET_SPARC64 */
|
||||
|
||||
/* 41 bit physical address space */
|
||||
static inline hwaddr ultrasparc_truncate_physical(uint64_t x)
|
||||
{
|
||||
return x & 0x1ffffffffffULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* UltraSparc IIi I/DMMUs
|
||||
*/
|
||||
|
||||
/* Returns true if TTE tag is valid and matches virtual address value
|
||||
in context requires virtual address mask value calculated from TTE
|
||||
entry size */
|
||||
static inline int ultrasparc_tag_match(SparcTLBEntry *tlb,
|
||||
uint64_t address, uint64_t context,
|
||||
hwaddr *physical)
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
uint64_t mask = 0 - (8192ULL << 3 * TTE_PGSIZE(tlb->tte));
|
||||
#else
|
||||
uint64_t mask = -(8192ULL << 3 * TTE_PGSIZE(tlb->tte));
|
||||
#endif
|
||||
|
||||
/* valid, context match, virtual address match? */
|
||||
if (TTE_IS_VALID(tlb->tte) &&
|
||||
(TTE_IS_GLOBAL(tlb->tte) || tlb_compare_context(tlb, context))
|
||||
&& compare_masked(address, tlb->tag, mask)) {
|
||||
/* decode physical address */
|
||||
*physical = ((tlb->tte & mask) | (address & ~mask)) & 0x1ffffffe000ULL;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_physical_address_data(CPUSPARCState *env, hwaddr *physical,
|
||||
int *prot, MemTxAttrs *attrs,
|
||||
target_ulong address, int rw, int mmu_idx)
|
||||
{
|
||||
CPUState *cs = env_cpu(env);
|
||||
unsigned int i;
|
||||
uint64_t context;
|
||||
uint64_t sfsr = 0;
|
||||
bool is_user = false;
|
||||
|
||||
switch (mmu_idx) {
|
||||
case MMU_PHYS_IDX:
|
||||
g_assert_not_reached();
|
||||
case MMU_USER_IDX:
|
||||
is_user = true;
|
||||
/* fallthru */
|
||||
case MMU_KERNEL_IDX:
|
||||
context = env->dmmu.mmu_primary_context & 0x1fff;
|
||||
sfsr |= SFSR_CT_PRIMARY;
|
||||
break;
|
||||
case MMU_USER_SECONDARY_IDX:
|
||||
is_user = true;
|
||||
/* fallthru */
|
||||
case MMU_KERNEL_SECONDARY_IDX:
|
||||
context = env->dmmu.mmu_secondary_context & 0x1fff;
|
||||
sfsr |= SFSR_CT_SECONDARY;
|
||||
break;
|
||||
case MMU_NUCLEUS_IDX:
|
||||
sfsr |= SFSR_CT_NUCLEUS;
|
||||
/* FALLTHRU */
|
||||
default:
|
||||
context = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (rw == 1) {
|
||||
sfsr |= SFSR_WRITE_BIT;
|
||||
} else if (rw == 4) {
|
||||
sfsr |= SFSR_NF_BIT;
|
||||
}
|
||||
|
||||
for (i = 0; i < 64; i++) {
|
||||
/* ctx match, vaddr match, valid? */
|
||||
if (ultrasparc_tag_match(&env->dtlb[i], address, context, physical)) {
|
||||
int do_fault = 0;
|
||||
|
||||
if (TTE_IS_IE(env->dtlb[i].tte)) {
|
||||
attrs->byte_swap = true;
|
||||
}
|
||||
|
||||
/* access ok? */
|
||||
/* multiple bits in SFSR.FT may be set on TT_DFAULT */
|
||||
if (TTE_IS_PRIV(env->dtlb[i].tte) && is_user) {
|
||||
do_fault = 1;
|
||||
sfsr |= SFSR_FT_PRIV_BIT; /* privilege violation */
|
||||
}
|
||||
if (rw == 4) {
|
||||
if (TTE_IS_SIDEEFFECT(env->dtlb[i].tte)) {
|
||||
do_fault = 1;
|
||||
sfsr |= SFSR_FT_NF_E_BIT;
|
||||
}
|
||||
} else {
|
||||
if (TTE_IS_NFO(env->dtlb[i].tte)) {
|
||||
do_fault = 1;
|
||||
sfsr |= SFSR_FT_NFO_BIT;
|
||||
}
|
||||
}
|
||||
|
||||
if (do_fault) {
|
||||
/* faults above are reported with TT_DFAULT. */
|
||||
cs->exception_index = TT_DFAULT;
|
||||
} else if (!TTE_IS_W_OK(env->dtlb[i].tte) && (rw == 1)) {
|
||||
do_fault = 1;
|
||||
cs->exception_index = TT_DPROT;
|
||||
}
|
||||
|
||||
if (!do_fault) {
|
||||
*prot = PAGE_READ;
|
||||
if (TTE_IS_W_OK(env->dtlb[i].tte)) {
|
||||
*prot |= PAGE_WRITE;
|
||||
}
|
||||
|
||||
TTE_SET_USED(env->dtlb[i].tte);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (env->dmmu.sfsr & SFSR_VALID_BIT) { /* Fault status register */
|
||||
sfsr |= SFSR_OW_BIT; /* overflow (not read before
|
||||
another fault) */
|
||||
}
|
||||
|
||||
if (env->pstate & PS_PRIV) {
|
||||
sfsr |= SFSR_PR_BIT;
|
||||
}
|
||||
|
||||
/* FIXME: ASI field in SFSR must be set */
|
||||
env->dmmu.sfsr = sfsr | SFSR_VALID_BIT;
|
||||
|
||||
env->dmmu.sfar = address; /* Fault address register */
|
||||
|
||||
env->dmmu.tag_access = (address & ~0x1fffULL) | context;
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* On MMU misses:
|
||||
* - UltraSPARC IIi: SFSR and SFAR unmodified
|
||||
* - JPS1: SFAR updated and some fields of SFSR updated
|
||||
*/
|
||||
env->dmmu.tag_access = (address & ~0x1fffULL) | context;
|
||||
cs->exception_index = TT_DMISS;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int get_physical_address_code(CPUSPARCState *env, hwaddr *physical,
|
||||
int *prot, MemTxAttrs *attrs,
|
||||
target_ulong address, int mmu_idx)
|
||||
{
|
||||
CPUState *cs = env_cpu(env);
|
||||
unsigned int i;
|
||||
uint64_t context;
|
||||
bool is_user = false;
|
||||
|
||||
switch (mmu_idx) {
|
||||
case MMU_PHYS_IDX:
|
||||
case MMU_USER_SECONDARY_IDX:
|
||||
case MMU_KERNEL_SECONDARY_IDX:
|
||||
g_assert_not_reached();
|
||||
case MMU_USER_IDX:
|
||||
is_user = true;
|
||||
/* fallthru */
|
||||
case MMU_KERNEL_IDX:
|
||||
context = env->dmmu.mmu_primary_context & 0x1fff;
|
||||
break;
|
||||
default:
|
||||
context = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (env->tl == 0) {
|
||||
/* PRIMARY context */
|
||||
context = env->dmmu.mmu_primary_context & 0x1fff;
|
||||
} else {
|
||||
/* NUCLEUS context */
|
||||
context = 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < 64; i++) {
|
||||
/* ctx match, vaddr match, valid? */
|
||||
if (ultrasparc_tag_match(&env->itlb[i],
|
||||
address, context, physical)) {
|
||||
/* access ok? */
|
||||
if (TTE_IS_PRIV(env->itlb[i].tte) && is_user) {
|
||||
/* Fault status register */
|
||||
if (env->immu.sfsr & SFSR_VALID_BIT) {
|
||||
env->immu.sfsr = SFSR_OW_BIT; /* overflow (not read before
|
||||
another fault) */
|
||||
} else {
|
||||
env->immu.sfsr = 0;
|
||||
}
|
||||
if (env->pstate & PS_PRIV) {
|
||||
env->immu.sfsr |= SFSR_PR_BIT;
|
||||
}
|
||||
if (env->tl > 0) {
|
||||
env->immu.sfsr |= SFSR_CT_NUCLEUS;
|
||||
}
|
||||
|
||||
/* FIXME: ASI field in SFSR must be set */
|
||||
env->immu.sfsr |= SFSR_FT_PRIV_BIT | SFSR_VALID_BIT;
|
||||
cs->exception_index = TT_TFAULT;
|
||||
|
||||
env->immu.tag_access = (address & ~0x1fffULL) | context;
|
||||
|
||||
return 1;
|
||||
}
|
||||
*prot = PAGE_EXEC;
|
||||
TTE_SET_USED(env->itlb[i].tte);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Context is stored in DMMU (dmmuregs[1]) also for IMMU */
|
||||
env->immu.tag_access = (address & ~0x1fffULL) | context;
|
||||
cs->exception_index = TT_TMISS;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int get_physical_address(CPUSPARCState *env, hwaddr *physical,
|
||||
int *prot, int *access_index, MemTxAttrs *attrs,
|
||||
target_ulong address, int rw, int mmu_idx,
|
||||
target_ulong *page_size)
|
||||
{
|
||||
/* ??? We treat everything as a small page, then explicitly flush
|
||||
everything when an entry is evicted. */
|
||||
*page_size = TARGET_PAGE_SIZE;
|
||||
|
||||
#if 0
|
||||
/* safety net to catch wrong softmmu index use from dynamic code */
|
||||
if (env->tl > 0 && mmu_idx != MMU_NUCLEUS_IDX) {
|
||||
if (rw == 2) {
|
||||
trace_mmu_helper_get_phys_addr_code(env->tl, mmu_idx,
|
||||
env->dmmu.mmu_primary_context,
|
||||
env->dmmu.mmu_secondary_context,
|
||||
address);
|
||||
} else {
|
||||
trace_mmu_helper_get_phys_addr_data(env->tl, mmu_idx,
|
||||
env->dmmu.mmu_primary_context,
|
||||
env->dmmu.mmu_secondary_context,
|
||||
address);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (mmu_idx == MMU_PHYS_IDX) {
|
||||
*physical = ultrasparc_truncate_physical(address);
|
||||
*prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (rw == 2) {
|
||||
return get_physical_address_code(env, physical, prot, attrs, address,
|
||||
mmu_idx);
|
||||
} else {
|
||||
return get_physical_address_data(env, physical, prot, attrs, address,
|
||||
rw, mmu_idx);
|
||||
}
|
||||
}
|
||||
|
||||
/* Perform address translation */
|
||||
bool sparc_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
||||
MMUAccessType access_type, int mmu_idx,
|
||||
bool probe, uintptr_t retaddr)
|
||||
{
|
||||
SPARCCPU *cpu = SPARC_CPU(cs);
|
||||
CPUSPARCState *env = &cpu->env;
|
||||
target_ulong vaddr;
|
||||
hwaddr paddr;
|
||||
target_ulong page_size;
|
||||
MemTxAttrs attrs = { 0 };
|
||||
int error_code = 0, prot, access_index;
|
||||
|
||||
address &= TARGET_PAGE_MASK;
|
||||
error_code = get_physical_address(env, &paddr, &prot, &access_index, &attrs,
|
||||
address, access_type,
|
||||
mmu_idx, &page_size);
|
||||
if (likely(error_code == 0)) {
|
||||
vaddr = address;
|
||||
|
||||
tlb_set_page_with_attrs(cs, vaddr, paddr, attrs, prot, mmu_idx,
|
||||
page_size);
|
||||
return true;
|
||||
}
|
||||
if (probe) {
|
||||
return false;
|
||||
}
|
||||
cpu_loop_exit_restore(cs, retaddr);
|
||||
}
|
||||
|
||||
#endif /* TARGET_SPARC64 */
|
||||
|
||||
static int cpu_sparc_get_phys_page(CPUSPARCState *env, hwaddr *phys,
|
||||
target_ulong addr, int rw, int mmu_idx)
|
||||
{
|
||||
target_ulong page_size;
|
||||
int prot, access_index;
|
||||
MemTxAttrs attrs = { 0 };
|
||||
|
||||
return get_physical_address(env, phys, &prot, &access_index, &attrs, addr,
|
||||
rw, mmu_idx, &page_size);
|
||||
}
|
||||
|
||||
#if defined(TARGET_SPARC64)
|
||||
hwaddr cpu_get_phys_page_nofault(CPUSPARCState *env, target_ulong addr,
|
||||
int mmu_idx)
|
||||
{
|
||||
hwaddr phys_addr;
|
||||
|
||||
if (cpu_sparc_get_phys_page(env, &phys_addr, addr, 4, mmu_idx) != 0) {
|
||||
return -1;
|
||||
}
|
||||
return phys_addr;
|
||||
}
|
||||
#endif
|
||||
|
||||
hwaddr sparc_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
|
||||
{
|
||||
SPARCCPU *cpu = SPARC_CPU(cs);
|
||||
CPUSPARCState *env = &cpu->env;
|
||||
hwaddr phys_addr;
|
||||
int mmu_idx = cpu_mmu_index(env, false);
|
||||
|
||||
if (cpu_sparc_get_phys_page(env, &phys_addr, addr, 2, mmu_idx) != 0) {
|
||||
if (cpu_sparc_get_phys_page(env, &phys_addr, addr, 0, mmu_idx) != 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return phys_addr;
|
||||
}
|
||||
6165
qemu/target/sparc/translate.c
Normal file
6165
qemu/target/sparc/translate.c
Normal file
File diff suppressed because it is too large
Load Diff
191
qemu/target/sparc/unicorn.c
Normal file
191
qemu/target/sparc/unicorn.c
Normal file
@@ -0,0 +1,191 @@
|
||||
/* Unicorn Emulator Engine */
|
||||
/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2015 */
|
||||
/* Modified for Unicorn Engine by Chen Huitao<chenhuitao@hfmrit.com>, 2020 */
|
||||
|
||||
#include "sysemu/cpus.h"
|
||||
#include "cpu.h"
|
||||
#include "unicorn_common.h"
|
||||
#include "uc_priv.h"
|
||||
#include "unicorn.h"
|
||||
|
||||
static bool sparc_stop_interrupt(struct uc_struct *uc, int intno)
|
||||
{
|
||||
switch(intno) {
|
||||
default:
|
||||
return false;
|
||||
case TT_ILL_INSN:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
static void sparc_set_pc(struct uc_struct *uc, uint64_t address)
|
||||
{
|
||||
((CPUSPARCState *)uc->cpu->env_ptr)->pc = address;
|
||||
((CPUSPARCState *)uc->cpu->env_ptr)->npc = address + 4;
|
||||
}
|
||||
|
||||
static void sparc_release(void *ctx)
|
||||
{
|
||||
int i;
|
||||
TCGContext *tcg_ctx = (TCGContext *)ctx;
|
||||
SPARCCPU *cpu = (SPARCCPU *)tcg_ctx->uc->cpu;
|
||||
CPUTLBDesc *d = cpu->neg.tlb.d;
|
||||
CPUTLBDescFast *f = cpu->neg.tlb.f;
|
||||
CPUTLBDesc *desc;
|
||||
CPUTLBDescFast *fast;
|
||||
|
||||
release_common(ctx);
|
||||
for (i = 0; i < NB_MMU_MODES; i++) {
|
||||
desc = &(d[i]);
|
||||
fast = &(f[i]);
|
||||
g_free(desc->iotlb);
|
||||
g_free(fast->table);
|
||||
}
|
||||
}
|
||||
|
||||
void sparc_reg_reset(struct uc_struct *uc)
|
||||
{
|
||||
CPUArchState *env = uc->cpu->env_ptr;
|
||||
|
||||
memset(env->gregs, 0, sizeof(env->gregs));
|
||||
memset(env->fpr, 0, sizeof(env->fpr));
|
||||
memset(env->regbase, 0, sizeof(env->regbase));
|
||||
|
||||
env->pc = 0;
|
||||
env->npc = 0;
|
||||
env->regwptr = env->regbase;
|
||||
}
|
||||
|
||||
static void reg_read(CPUSPARCState *env, unsigned int regid, void *value)
|
||||
{
|
||||
if (regid >= UC_SPARC_REG_G0 && regid <= UC_SPARC_REG_G7)
|
||||
*(int32_t *)value = env->gregs[regid - UC_SPARC_REG_G0];
|
||||
else if (regid >= UC_SPARC_REG_O0 && regid <= UC_SPARC_REG_O7)
|
||||
*(int32_t *)value = env->regwptr[regid - UC_SPARC_REG_O0];
|
||||
else if (regid >= UC_SPARC_REG_L0 && regid <= UC_SPARC_REG_L7)
|
||||
*(int32_t *)value = env->regwptr[8 + regid - UC_SPARC_REG_L0];
|
||||
else if (regid >= UC_SPARC_REG_I0 && regid <= UC_SPARC_REG_I7)
|
||||
*(int32_t *)value = env->regwptr[16 + regid - UC_SPARC_REG_I0];
|
||||
else {
|
||||
switch(regid) {
|
||||
default: break;
|
||||
case UC_SPARC_REG_PC:
|
||||
*(int32_t *)value = env->pc;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void reg_write(CPUSPARCState *env, unsigned int regid, const void *value)
|
||||
{
|
||||
if (regid >= UC_SPARC_REG_G0 && regid <= UC_SPARC_REG_G7)
|
||||
env->gregs[regid - UC_SPARC_REG_G0] = *(uint32_t *)value;
|
||||
else if (regid >= UC_SPARC_REG_O0 && regid <= UC_SPARC_REG_O7)
|
||||
env->regwptr[regid - UC_SPARC_REG_O0] = *(uint32_t *)value;
|
||||
else if (regid >= UC_SPARC_REG_L0 && regid <= UC_SPARC_REG_L7)
|
||||
env->regwptr[8 + regid - UC_SPARC_REG_L0] = *(uint32_t *)value;
|
||||
else if (regid >= UC_SPARC_REG_I0 && regid <= UC_SPARC_REG_I7)
|
||||
env->regwptr[16 + regid - UC_SPARC_REG_I0] = *(uint32_t *)value;
|
||||
else {
|
||||
switch(regid) {
|
||||
default: break;
|
||||
case UC_SPARC_REG_PC:
|
||||
env->pc = *(uint32_t *)value;
|
||||
env->npc = *(uint32_t *)value + 4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int sparc_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count)
|
||||
{
|
||||
CPUSPARCState *env = &(SPARC_CPU(uc->cpu)->env);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
unsigned int regid = regs[i];
|
||||
void *value = vals[i];
|
||||
reg_read(env, regid, value);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sparc_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, int count)
|
||||
{
|
||||
CPUSPARCState *env = &(SPARC_CPU(uc->cpu)->env);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
unsigned int regid = regs[i];
|
||||
const void *value = vals[i];
|
||||
reg_write(env, regid, value);
|
||||
if( regid == UC_SPARC_REG_PC){
|
||||
// force to quit execution and flush TB
|
||||
uc->quit_request = true;
|
||||
uc_emu_stop(uc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFAULT_VISIBILITY
|
||||
int sparc_context_reg_read(struct uc_context *ctx, unsigned int *regs, void **vals, int count)
|
||||
{
|
||||
CPUSPARCState *env = (CPUSPARCState *)ctx->data;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
unsigned int regid = regs[i];
|
||||
void *value = vals[i];
|
||||
reg_read(env, regid, value);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFAULT_VISIBILITY
|
||||
int sparc_context_reg_write(struct uc_context *ctx, unsigned int *regs, void *const *vals, int count)
|
||||
{
|
||||
CPUSPARCState *env = (CPUSPARCState *)ctx->data;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
unsigned int regid = regs[i];
|
||||
const void *value = vals[i];
|
||||
reg_write(env, regid, value);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sparc_cpus_init(struct uc_struct *uc, const char *cpu_model)
|
||||
{
|
||||
SPARCCPU *cpu;
|
||||
|
||||
cpu = cpu_sparc_init(uc, cpu_model);
|
||||
if (cpu == NULL) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFAULT_VISIBILITY
|
||||
void sparc_uc_init(struct uc_struct* uc)
|
||||
{
|
||||
uc->release = sparc_release;
|
||||
uc->reg_read = sparc_reg_read;
|
||||
uc->reg_write = sparc_reg_write;
|
||||
uc->reg_reset = sparc_reg_reset;
|
||||
uc->set_pc = sparc_set_pc;
|
||||
uc->stop_interrupt = sparc_stop_interrupt;
|
||||
uc->cpus_init = sparc_cpus_init;
|
||||
uc->cpu_context_size = offsetof(CPUSPARCState, irq_manager);
|
||||
uc_common_init(uc);
|
||||
}
|
||||
20
qemu/target/sparc/unicorn.h
Normal file
20
qemu/target/sparc/unicorn.h
Normal file
@@ -0,0 +1,20 @@
|
||||
/* Unicorn Emulator Engine */
|
||||
/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2015 */
|
||||
|
||||
#ifndef UC_QEMU_TARGET_SPARC_H
|
||||
#define UC_QEMU_TARGET_SPARC_H
|
||||
|
||||
// functions to read & write registers
|
||||
int sparc_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count);
|
||||
int sparc_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, int count);
|
||||
|
||||
int sparc_context_reg_read(struct uc_context *ctx, unsigned int *regs, void **vals, int count);
|
||||
int sparc_context_reg_write(struct uc_context *ctx, unsigned int *regs, void *const *vals, int count);
|
||||
int sparc64_context_reg_read(struct uc_context *ctx, unsigned int *regs, void **vals, int count);
|
||||
int sparc64_context_reg_write(struct uc_context *ctx, unsigned int *regs, void *const *vals, int count);
|
||||
|
||||
void sparc_reg_reset(struct uc_struct *uc);
|
||||
|
||||
void sparc_uc_init(struct uc_struct* uc);
|
||||
void sparc64_uc_init(struct uc_struct* uc);
|
||||
#endif
|
||||
202
qemu/target/sparc/unicorn64.c
Normal file
202
qemu/target/sparc/unicorn64.c
Normal file
@@ -0,0 +1,202 @@
|
||||
/* Unicorn Emulator Engine */
|
||||
/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2015 */
|
||||
/* Modified for Unicorn Engine by Chen Huitao<chenhuitao@hfmrit.com>, 2020 */
|
||||
|
||||
#include "sysemu/cpus.h"
|
||||
#include "cpu.h"
|
||||
#include "unicorn_common.h"
|
||||
#include "uc_priv.h"
|
||||
#include "unicorn.h"
|
||||
|
||||
const int SPARC64_REGS_STORAGE_SIZE = offsetof(CPUSPARCState, irq_manager);
|
||||
|
||||
static bool sparc_stop_interrupt(struct uc_struct *uc, int intno)
|
||||
{
|
||||
switch(intno) {
|
||||
default:
|
||||
return false;
|
||||
case TT_ILL_INSN:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
static void sparc_set_pc(struct uc_struct *uc, uint64_t address)
|
||||
{
|
||||
((CPUSPARCState *)uc->cpu->env_ptr)->pc = address;
|
||||
((CPUSPARCState *)uc->cpu->env_ptr)->npc = address + 4;
|
||||
}
|
||||
|
||||
static void sparc_release(void *ctx)
|
||||
{
|
||||
release_common(ctx);
|
||||
|
||||
#if 0
|
||||
int i;
|
||||
TCGContext *tcg_ctx = (TCGContext *) ctx;
|
||||
SPARCCPU *cpu = SPARC_CPU(tcg_ctx->uc->cpu);
|
||||
CPUSPARCState *env = &cpu->env;
|
||||
|
||||
g_free(tcg_ctx->cpu_wim);
|
||||
g_free(tcg_ctx->cpu_cond);
|
||||
g_free(tcg_ctx->cpu_cc_src);
|
||||
g_free(tcg_ctx->cpu_cc_src2);
|
||||
g_free(tcg_ctx->cpu_cc_dst);
|
||||
g_free(tcg_ctx->cpu_fsr);
|
||||
g_free(tcg_ctx->sparc_cpu_pc);
|
||||
g_free(tcg_ctx->cpu_npc);
|
||||
g_free(tcg_ctx->cpu_y);
|
||||
g_free(tcg_ctx->cpu_tbr);
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
g_free(tcg_ctx->cpu_gregs[i]);
|
||||
}
|
||||
for (i = 0; i < 32; i++) {
|
||||
g_free(tcg_ctx->cpu_gpr[i]);
|
||||
}
|
||||
|
||||
g_free(tcg_ctx->cpu_PC);
|
||||
g_free(tcg_ctx->btarget);
|
||||
g_free(tcg_ctx->bcond);
|
||||
g_free(tcg_ctx->cpu_dspctrl);
|
||||
|
||||
g_free(tcg_ctx->tb_ctx.tbs);
|
||||
|
||||
g_free(env->def);
|
||||
#endif
|
||||
}
|
||||
|
||||
void sparc_reg_reset(struct uc_struct *uc)
|
||||
{
|
||||
CPUArchState *env = uc->cpu->env_ptr;
|
||||
|
||||
memset(env->gregs, 0, sizeof(env->gregs));
|
||||
memset(env->fpr, 0, sizeof(env->fpr));
|
||||
memset(env->regbase, 0, sizeof(env->regbase));
|
||||
|
||||
env->pc = 0;
|
||||
env->npc = 0;
|
||||
env->regwptr = env->regbase;
|
||||
}
|
||||
|
||||
static void reg_read(CPUSPARCState *env, unsigned int regid, void *value)
|
||||
{
|
||||
if (regid >= UC_SPARC_REG_G0 && regid <= UC_SPARC_REG_G7)
|
||||
*(int64_t *)value = env->gregs[regid - UC_SPARC_REG_G0];
|
||||
else if (regid >= UC_SPARC_REG_O0 && regid <= UC_SPARC_REG_O7)
|
||||
*(int64_t *)value = env->regwptr[regid - UC_SPARC_REG_O0];
|
||||
else if (regid >= UC_SPARC_REG_L0 && regid <= UC_SPARC_REG_L7)
|
||||
*(int64_t *)value = env->regwptr[8 + regid - UC_SPARC_REG_L0];
|
||||
else if (regid >= UC_SPARC_REG_I0 && regid <= UC_SPARC_REG_I7)
|
||||
*(int64_t *)value = env->regwptr[16 + regid - UC_SPARC_REG_I0];
|
||||
else {
|
||||
switch(regid) {
|
||||
default: break;
|
||||
case UC_SPARC_REG_PC:
|
||||
*(int64_t *)value = env->pc;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void reg_write(CPUSPARCState *env, unsigned int regid, const void *value)
|
||||
{
|
||||
if (regid >= UC_SPARC_REG_G0 && regid <= UC_SPARC_REG_G7)
|
||||
env->gregs[regid - UC_SPARC_REG_G0] = *(uint64_t *)value;
|
||||
else if (regid >= UC_SPARC_REG_O0 && regid <= UC_SPARC_REG_O7)
|
||||
env->regwptr[regid - UC_SPARC_REG_O0] = *(uint64_t *)value;
|
||||
else if (regid >= UC_SPARC_REG_L0 && regid <= UC_SPARC_REG_L7)
|
||||
env->regwptr[8 + regid - UC_SPARC_REG_L0] = *(uint64_t *)value;
|
||||
else if (regid >= UC_SPARC_REG_I0 && regid <= UC_SPARC_REG_I7)
|
||||
env->regwptr[16 + regid - UC_SPARC_REG_I0] = *(uint64_t *)value;
|
||||
else {
|
||||
switch(regid) {
|
||||
default: break;
|
||||
case UC_SPARC_REG_PC:
|
||||
env->pc = *(uint64_t *)value;
|
||||
env->npc = *(uint64_t *)value + 4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int sparc_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count)
|
||||
{
|
||||
CPUSPARCState *env = &(SPARC_CPU(uc->cpu)->env);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
unsigned int regid = regs[i];
|
||||
void *value = vals[i];
|
||||
reg_read(env, regid, value);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sparc_reg_write(struct uc_struct *uc, unsigned int *regs, void* const* vals, int count)
|
||||
{
|
||||
CPUSPARCState *env = &(SPARC_CPU(uc->cpu)->env);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
unsigned int regid = regs[i];
|
||||
const void *value = vals[i];
|
||||
reg_write(env, regid, value);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFAULT_VISIBILITY
|
||||
int sparc64_context_reg_read(struct uc_context *ctx, unsigned int *regs, void **vals, int count)
|
||||
{
|
||||
CPUSPARCState *env = (CPUSPARCState *)ctx->data;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
unsigned int regid = regs[i];
|
||||
void *value = vals[i];
|
||||
reg_read(env, regid, value);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFAULT_VISIBILITY
|
||||
int sparc64_context_reg_write(struct uc_context *ctx, unsigned int *regs, void *const *vals, int count)
|
||||
{
|
||||
CPUSPARCState *env = (CPUSPARCState *)ctx->data;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
unsigned int regid = regs[i];
|
||||
const void *value = vals[i];
|
||||
reg_write(env, regid, value);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sparc_cpus_init(struct uc_struct *uc, const char *cpu_model)
|
||||
{
|
||||
SPARCCPU *cpu;
|
||||
|
||||
cpu = cpu_sparc_init(uc, cpu_model);
|
||||
if (cpu == NULL) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFAULT_VISIBILITY
|
||||
void sparc64_uc_init(struct uc_struct* uc)
|
||||
{
|
||||
uc->release = sparc_release;
|
||||
uc->reg_read = sparc_reg_read;
|
||||
uc->reg_write = sparc_reg_write;
|
||||
uc->reg_reset = sparc_reg_reset;
|
||||
uc->set_pc = sparc_set_pc;
|
||||
uc->stop_interrupt = sparc_stop_interrupt;
|
||||
uc->cpus_init = sparc_cpus_init;
|
||||
uc_common_init(uc);
|
||||
}
|
||||
490
qemu/target/sparc/vis_helper.c
Normal file
490
qemu/target/sparc/vis_helper.c
Normal file
@@ -0,0 +1,490 @@
|
||||
/*
|
||||
* VIS op helpers
|
||||
*
|
||||
* Copyright (c) 2003-2005 Fabrice Bellard
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "cpu.h"
|
||||
#include "exec/helper-proto.h"
|
||||
|
||||
/* This function uses non-native bit order */
|
||||
#define GET_FIELD(X, FROM, TO) \
|
||||
((X) >> (63 - (TO)) & ((1ULL << ((TO) - (FROM) + 1)) - 1))
|
||||
|
||||
/* This function uses the order in the manuals, i.e. bit 0 is 2^0 */
|
||||
#define GET_FIELD_SP(X, FROM, TO) \
|
||||
GET_FIELD(X, 63 - (TO), 63 - (FROM))
|
||||
|
||||
target_ulong helper_array8(target_ulong pixel_addr, target_ulong cubesize)
|
||||
{
|
||||
return (GET_FIELD_SP(pixel_addr, 60, 63) << (17 + 2 * cubesize)) |
|
||||
(GET_FIELD_SP(pixel_addr, 39, 39 + cubesize - 1) << (17 + cubesize)) |
|
||||
(GET_FIELD_SP(pixel_addr, 17 + cubesize - 1, 17) << 17) |
|
||||
(GET_FIELD_SP(pixel_addr, 56, 59) << 13) |
|
||||
(GET_FIELD_SP(pixel_addr, 35, 38) << 9) |
|
||||
(GET_FIELD_SP(pixel_addr, 13, 16) << 5) |
|
||||
(((pixel_addr >> 55) & 1) << 4) |
|
||||
(GET_FIELD_SP(pixel_addr, 33, 34) << 2) |
|
||||
GET_FIELD_SP(pixel_addr, 11, 12);
|
||||
}
|
||||
|
||||
#ifdef HOST_WORDS_BIGENDIAN
|
||||
#define VIS_B64(n) b[7 - (n)]
|
||||
#define VIS_W64(n) w[3 - (n)]
|
||||
#define VIS_SW64(n) sw[3 - (n)]
|
||||
#define VIS_L64(n) l[1 - (n)]
|
||||
#define VIS_B32(n) b[3 - (n)]
|
||||
#define VIS_W32(n) w[1 - (n)]
|
||||
#else
|
||||
#define VIS_B64(n) b[n]
|
||||
#define VIS_W64(n) w[n]
|
||||
#define VIS_SW64(n) sw[n]
|
||||
#define VIS_L64(n) l[n]
|
||||
#define VIS_B32(n) b[n]
|
||||
#define VIS_W32(n) w[n]
|
||||
#endif
|
||||
|
||||
typedef union {
|
||||
uint8_t b[8];
|
||||
uint16_t w[4];
|
||||
int16_t sw[4];
|
||||
uint32_t l[2];
|
||||
uint64_t ll;
|
||||
float64 d;
|
||||
} VIS64;
|
||||
|
||||
typedef union {
|
||||
uint8_t b[4];
|
||||
uint16_t w[2];
|
||||
uint32_t l;
|
||||
float32 f;
|
||||
} VIS32;
|
||||
|
||||
uint64_t helper_fpmerge(uint64_t src1, uint64_t src2)
|
||||
{
|
||||
VIS64 s, d;
|
||||
|
||||
s.ll = src1;
|
||||
d.ll = src2;
|
||||
|
||||
/* Reverse calculation order to handle overlap */
|
||||
d.VIS_B64(7) = s.VIS_B64(3);
|
||||
d.VIS_B64(6) = d.VIS_B64(3);
|
||||
d.VIS_B64(5) = s.VIS_B64(2);
|
||||
d.VIS_B64(4) = d.VIS_B64(2);
|
||||
d.VIS_B64(3) = s.VIS_B64(1);
|
||||
d.VIS_B64(2) = d.VIS_B64(1);
|
||||
d.VIS_B64(1) = s.VIS_B64(0);
|
||||
/* d.VIS_B64(0) = d.VIS_B64(0); */
|
||||
|
||||
return d.ll;
|
||||
}
|
||||
|
||||
uint64_t helper_fmul8x16(uint64_t src1, uint64_t src2)
|
||||
{
|
||||
VIS64 s, d;
|
||||
uint32_t tmp;
|
||||
|
||||
s.ll = src1;
|
||||
d.ll = src2;
|
||||
|
||||
#define PMUL(r) \
|
||||
tmp = (int32_t)d.VIS_SW64(r) * (int32_t)s.VIS_B64(r); \
|
||||
if ((tmp & 0xff) > 0x7f) { \
|
||||
tmp += 0x100; \
|
||||
} \
|
||||
d.VIS_W64(r) = tmp >> 8;
|
||||
|
||||
PMUL(0);
|
||||
PMUL(1);
|
||||
PMUL(2);
|
||||
PMUL(3);
|
||||
#undef PMUL
|
||||
|
||||
return d.ll;
|
||||
}
|
||||
|
||||
uint64_t helper_fmul8x16al(uint64_t src1, uint64_t src2)
|
||||
{
|
||||
VIS64 s, d;
|
||||
uint32_t tmp;
|
||||
|
||||
s.ll = src1;
|
||||
d.ll = src2;
|
||||
|
||||
#define PMUL(r) \
|
||||
tmp = (int32_t)d.VIS_SW64(1) * (int32_t)s.VIS_B64(r); \
|
||||
if ((tmp & 0xff) > 0x7f) { \
|
||||
tmp += 0x100; \
|
||||
} \
|
||||
d.VIS_W64(r) = tmp >> 8;
|
||||
|
||||
PMUL(0);
|
||||
PMUL(1);
|
||||
PMUL(2);
|
||||
PMUL(3);
|
||||
#undef PMUL
|
||||
|
||||
return d.ll;
|
||||
}
|
||||
|
||||
uint64_t helper_fmul8x16au(uint64_t src1, uint64_t src2)
|
||||
{
|
||||
VIS64 s, d;
|
||||
uint32_t tmp;
|
||||
|
||||
s.ll = src1;
|
||||
d.ll = src2;
|
||||
|
||||
#define PMUL(r) \
|
||||
tmp = (int32_t)d.VIS_SW64(0) * (int32_t)s.VIS_B64(r); \
|
||||
if ((tmp & 0xff) > 0x7f) { \
|
||||
tmp += 0x100; \
|
||||
} \
|
||||
d.VIS_W64(r) = tmp >> 8;
|
||||
|
||||
PMUL(0);
|
||||
PMUL(1);
|
||||
PMUL(2);
|
||||
PMUL(3);
|
||||
#undef PMUL
|
||||
|
||||
return d.ll;
|
||||
}
|
||||
|
||||
uint64_t helper_fmul8sux16(uint64_t src1, uint64_t src2)
|
||||
{
|
||||
VIS64 s, d;
|
||||
uint32_t tmp;
|
||||
|
||||
s.ll = src1;
|
||||
d.ll = src2;
|
||||
|
||||
#define PMUL(r) \
|
||||
tmp = (int32_t)d.VIS_SW64(r) * ((int32_t)s.VIS_SW64(r) >> 8); \
|
||||
if ((tmp & 0xff) > 0x7f) { \
|
||||
tmp += 0x100; \
|
||||
} \
|
||||
d.VIS_W64(r) = tmp >> 8;
|
||||
|
||||
PMUL(0);
|
||||
PMUL(1);
|
||||
PMUL(2);
|
||||
PMUL(3);
|
||||
#undef PMUL
|
||||
|
||||
return d.ll;
|
||||
}
|
||||
|
||||
uint64_t helper_fmul8ulx16(uint64_t src1, uint64_t src2)
|
||||
{
|
||||
VIS64 s, d;
|
||||
uint32_t tmp;
|
||||
|
||||
s.ll = src1;
|
||||
d.ll = src2;
|
||||
|
||||
#define PMUL(r) \
|
||||
tmp = (int32_t)d.VIS_SW64(r) * ((uint32_t)s.VIS_B64(r * 2)); \
|
||||
if ((tmp & 0xff) > 0x7f) { \
|
||||
tmp += 0x100; \
|
||||
} \
|
||||
d.VIS_W64(r) = tmp >> 8;
|
||||
|
||||
PMUL(0);
|
||||
PMUL(1);
|
||||
PMUL(2);
|
||||
PMUL(3);
|
||||
#undef PMUL
|
||||
|
||||
return d.ll;
|
||||
}
|
||||
|
||||
uint64_t helper_fmuld8sux16(uint64_t src1, uint64_t src2)
|
||||
{
|
||||
VIS64 s, d;
|
||||
uint32_t tmp;
|
||||
|
||||
s.ll = src1;
|
||||
d.ll = src2;
|
||||
|
||||
#define PMUL(r) \
|
||||
tmp = (int32_t)d.VIS_SW64(r) * ((int32_t)s.VIS_SW64(r) >> 8); \
|
||||
if ((tmp & 0xff) > 0x7f) { \
|
||||
tmp += 0x100; \
|
||||
} \
|
||||
d.VIS_L64(r) = tmp;
|
||||
|
||||
/* Reverse calculation order to handle overlap */
|
||||
PMUL(1);
|
||||
PMUL(0);
|
||||
#undef PMUL
|
||||
|
||||
return d.ll;
|
||||
}
|
||||
|
||||
uint64_t helper_fmuld8ulx16(uint64_t src1, uint64_t src2)
|
||||
{
|
||||
VIS64 s, d;
|
||||
uint32_t tmp;
|
||||
|
||||
s.ll = src1;
|
||||
d.ll = src2;
|
||||
|
||||
#define PMUL(r) \
|
||||
tmp = (int32_t)d.VIS_SW64(r) * ((uint32_t)s.VIS_B64(r * 2)); \
|
||||
if ((tmp & 0xff) > 0x7f) { \
|
||||
tmp += 0x100; \
|
||||
} \
|
||||
d.VIS_L64(r) = tmp;
|
||||
|
||||
/* Reverse calculation order to handle overlap */
|
||||
PMUL(1);
|
||||
PMUL(0);
|
||||
#undef PMUL
|
||||
|
||||
return d.ll;
|
||||
}
|
||||
|
||||
uint64_t helper_fexpand(uint64_t src1, uint64_t src2)
|
||||
{
|
||||
VIS32 s;
|
||||
VIS64 d;
|
||||
|
||||
s.l = (uint32_t)src1;
|
||||
d.ll = src2;
|
||||
d.VIS_W64(0) = s.VIS_B32(0) << 4;
|
||||
d.VIS_W64(1) = s.VIS_B32(1) << 4;
|
||||
d.VIS_W64(2) = s.VIS_B32(2) << 4;
|
||||
d.VIS_W64(3) = s.VIS_B32(3) << 4;
|
||||
|
||||
return d.ll;
|
||||
}
|
||||
|
||||
#define VIS_HELPER(name, F) \
|
||||
uint64_t name##16(uint64_t src1, uint64_t src2) \
|
||||
{ \
|
||||
VIS64 s, d; \
|
||||
\
|
||||
s.ll = src1; \
|
||||
d.ll = src2; \
|
||||
\
|
||||
d.VIS_W64(0) = F(d.VIS_W64(0), s.VIS_W64(0)); \
|
||||
d.VIS_W64(1) = F(d.VIS_W64(1), s.VIS_W64(1)); \
|
||||
d.VIS_W64(2) = F(d.VIS_W64(2), s.VIS_W64(2)); \
|
||||
d.VIS_W64(3) = F(d.VIS_W64(3), s.VIS_W64(3)); \
|
||||
\
|
||||
return d.ll; \
|
||||
} \
|
||||
\
|
||||
uint32_t name##16s(uint32_t src1, uint32_t src2) \
|
||||
{ \
|
||||
VIS32 s, d; \
|
||||
\
|
||||
s.l = src1; \
|
||||
d.l = src2; \
|
||||
\
|
||||
d.VIS_W32(0) = F(d.VIS_W32(0), s.VIS_W32(0)); \
|
||||
d.VIS_W32(1) = F(d.VIS_W32(1), s.VIS_W32(1)); \
|
||||
\
|
||||
return d.l; \
|
||||
} \
|
||||
\
|
||||
uint64_t name##32(uint64_t src1, uint64_t src2) \
|
||||
{ \
|
||||
VIS64 s, d; \
|
||||
\
|
||||
s.ll = src1; \
|
||||
d.ll = src2; \
|
||||
\
|
||||
d.VIS_L64(0) = F(d.VIS_L64(0), s.VIS_L64(0)); \
|
||||
d.VIS_L64(1) = F(d.VIS_L64(1), s.VIS_L64(1)); \
|
||||
\
|
||||
return d.ll; \
|
||||
} \
|
||||
\
|
||||
uint32_t name##32s(uint32_t src1, uint32_t src2) \
|
||||
{ \
|
||||
VIS32 s, d; \
|
||||
\
|
||||
s.l = src1; \
|
||||
d.l = src2; \
|
||||
\
|
||||
d.l = F(d.l, s.l); \
|
||||
\
|
||||
return d.l; \
|
||||
}
|
||||
|
||||
#define FADD(a, b) ((a) + (b))
|
||||
#define FSUB(a, b) ((a) - (b))
|
||||
VIS_HELPER(helper_fpadd, FADD)
|
||||
VIS_HELPER(helper_fpsub, FSUB)
|
||||
|
||||
#define VIS_CMPHELPER(name, F) \
|
||||
uint64_t name##16(uint64_t src1, uint64_t src2) \
|
||||
{ \
|
||||
VIS64 s, d; \
|
||||
\
|
||||
s.ll = src1; \
|
||||
d.ll = src2; \
|
||||
\
|
||||
d.VIS_W64(0) = F(s.VIS_W64(0), d.VIS_W64(0)) ? 1 : 0; \
|
||||
d.VIS_W64(0) |= F(s.VIS_W64(1), d.VIS_W64(1)) ? 2 : 0; \
|
||||
d.VIS_W64(0) |= F(s.VIS_W64(2), d.VIS_W64(2)) ? 4 : 0; \
|
||||
d.VIS_W64(0) |= F(s.VIS_W64(3), d.VIS_W64(3)) ? 8 : 0; \
|
||||
d.VIS_W64(1) = d.VIS_W64(2) = d.VIS_W64(3) = 0; \
|
||||
\
|
||||
return d.ll; \
|
||||
} \
|
||||
\
|
||||
uint64_t name##32(uint64_t src1, uint64_t src2) \
|
||||
{ \
|
||||
VIS64 s, d; \
|
||||
\
|
||||
s.ll = src1; \
|
||||
d.ll = src2; \
|
||||
\
|
||||
d.VIS_L64(0) = F(s.VIS_L64(0), d.VIS_L64(0)) ? 1 : 0; \
|
||||
d.VIS_L64(0) |= F(s.VIS_L64(1), d.VIS_L64(1)) ? 2 : 0; \
|
||||
d.VIS_L64(1) = 0; \
|
||||
\
|
||||
return d.ll; \
|
||||
}
|
||||
|
||||
#define FCMPGT(a, b) ((a) > (b))
|
||||
#define FCMPEQ(a, b) ((a) == (b))
|
||||
#define FCMPLE(a, b) ((a) <= (b))
|
||||
#define FCMPNE(a, b) ((a) != (b))
|
||||
|
||||
VIS_CMPHELPER(helper_fcmpgt, FCMPGT)
|
||||
VIS_CMPHELPER(helper_fcmpeq, FCMPEQ)
|
||||
VIS_CMPHELPER(helper_fcmple, FCMPLE)
|
||||
VIS_CMPHELPER(helper_fcmpne, FCMPNE)
|
||||
|
||||
uint64_t helper_pdist(uint64_t sum, uint64_t src1, uint64_t src2)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 8; i++) {
|
||||
int s1, s2;
|
||||
|
||||
s1 = (src1 >> (56 - (i * 8))) & 0xff;
|
||||
s2 = (src2 >> (56 - (i * 8))) & 0xff;
|
||||
|
||||
/* Absolute value of difference. */
|
||||
s1 -= s2;
|
||||
if (s1 < 0) {
|
||||
s1 = -s1;
|
||||
}
|
||||
|
||||
sum += s1;
|
||||
}
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
uint32_t helper_fpack16(uint64_t gsr, uint64_t rs2)
|
||||
{
|
||||
int scale = (gsr >> 3) & 0xf;
|
||||
uint32_t ret = 0;
|
||||
int byte;
|
||||
|
||||
for (byte = 0; byte < 4; byte++) {
|
||||
uint32_t val;
|
||||
int16_t src = rs2 >> (byte * 16);
|
||||
int32_t scaled = src << scale;
|
||||
int32_t from_fixed = scaled >> 7;
|
||||
|
||||
val = (from_fixed < 0 ? 0 :
|
||||
from_fixed > 255 ? 255 : from_fixed);
|
||||
|
||||
ret |= val << (8 * byte);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint64_t helper_fpack32(uint64_t gsr, uint64_t rs1, uint64_t rs2)
|
||||
{
|
||||
int scale = (gsr >> 3) & 0x1f;
|
||||
uint64_t ret = 0;
|
||||
int word;
|
||||
|
||||
ret = (rs1 << 8) & ~(0x000000ff000000ffULL);
|
||||
for (word = 0; word < 2; word++) {
|
||||
uint64_t val;
|
||||
int32_t src = rs2 >> (word * 32);
|
||||
int64_t scaled = (int64_t)src << scale;
|
||||
int64_t from_fixed = scaled >> 23;
|
||||
|
||||
val = (from_fixed < 0 ? 0 :
|
||||
(from_fixed > 255) ? 255 : from_fixed);
|
||||
|
||||
ret |= val << (32 * word);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t helper_fpackfix(uint64_t gsr, uint64_t rs2)
|
||||
{
|
||||
int scale = (gsr >> 3) & 0x1f;
|
||||
uint32_t ret = 0;
|
||||
int word;
|
||||
|
||||
for (word = 0; word < 2; word++) {
|
||||
uint32_t val;
|
||||
int32_t src = rs2 >> (word * 32);
|
||||
int64_t scaled = (int64_t)src << scale;
|
||||
int64_t from_fixed = scaled >> 16;
|
||||
|
||||
val = (from_fixed < -32768 ? -32768 :
|
||||
from_fixed > 32767 ? 32767 : from_fixed);
|
||||
|
||||
ret |= (val & 0xffff) << (word * 16);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint64_t helper_bshuffle(uint64_t gsr, uint64_t src1, uint64_t src2)
|
||||
{
|
||||
union {
|
||||
uint64_t ll[2];
|
||||
uint8_t b[16];
|
||||
} s;
|
||||
VIS64 r;
|
||||
uint32_t i, mask, host;
|
||||
|
||||
/* Set up S such that we can index across all of the bytes. */
|
||||
#ifdef HOST_WORDS_BIGENDIAN
|
||||
s.ll[0] = src1;
|
||||
s.ll[1] = src2;
|
||||
host = 0;
|
||||
#else
|
||||
s.ll[1] = src1;
|
||||
s.ll[0] = src2;
|
||||
host = 15;
|
||||
#endif
|
||||
mask = gsr >> 32;
|
||||
|
||||
for (i = 0; i < 8; ++i) {
|
||||
unsigned e = (mask >> (28 - i*4)) & 0xf;
|
||||
r.VIS_B64(i) = s.b[e ^ host];
|
||||
}
|
||||
|
||||
return r.ll;
|
||||
}
|
||||
424
qemu/target/sparc/win_helper.c
Normal file
424
qemu/target/sparc/win_helper.c
Normal file
@@ -0,0 +1,424 @@
|
||||
/*
|
||||
* Helpers for CWP and PSTATE handling
|
||||
*
|
||||
* Copyright (c) 2003-2005 Fabrice Bellard
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "cpu.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "exec/helper-proto.h"
|
||||
|
||||
static inline void memcpy32(target_ulong *dst, const target_ulong *src)
|
||||
{
|
||||
dst[0] = src[0];
|
||||
dst[1] = src[1];
|
||||
dst[2] = src[2];
|
||||
dst[3] = src[3];
|
||||
dst[4] = src[4];
|
||||
dst[5] = src[5];
|
||||
dst[6] = src[6];
|
||||
dst[7] = src[7];
|
||||
}
|
||||
|
||||
void cpu_set_cwp(CPUSPARCState *env, int new_cwp)
|
||||
{
|
||||
/* put the modified wrap registers at their proper location */
|
||||
if (env->cwp == env->nwindows - 1) {
|
||||
memcpy32(env->regbase, env->regbase + env->nwindows * 16);
|
||||
}
|
||||
env->cwp = new_cwp;
|
||||
|
||||
/* put the wrap registers at their temporary location */
|
||||
if (new_cwp == env->nwindows - 1) {
|
||||
memcpy32(env->regbase + env->nwindows * 16, env->regbase);
|
||||
}
|
||||
env->regwptr = env->regbase + (new_cwp * 16);
|
||||
}
|
||||
|
||||
target_ulong cpu_get_psr(CPUSPARCState *env)
|
||||
{
|
||||
helper_compute_psr(env);
|
||||
|
||||
#if !defined(TARGET_SPARC64)
|
||||
return env->version | (env->psr & PSR_ICC) |
|
||||
(env->psref ? PSR_EF : 0) |
|
||||
(env->psrpil << 8) |
|
||||
(env->psrs ? PSR_S : 0) |
|
||||
(env->psrps ? PSR_PS : 0) |
|
||||
(env->psret ? PSR_ET : 0) | env->cwp;
|
||||
#else
|
||||
return env->psr & PSR_ICC;
|
||||
#endif
|
||||
}
|
||||
|
||||
void cpu_put_psr_raw(CPUSPARCState *env, target_ulong val)
|
||||
{
|
||||
env->psr = val & PSR_ICC;
|
||||
#if !defined(TARGET_SPARC64)
|
||||
env->psref = (val & PSR_EF) ? 1 : 0;
|
||||
env->psrpil = (val & PSR_PIL) >> 8;
|
||||
env->psrs = (val & PSR_S) ? 1 : 0;
|
||||
env->psrps = (val & PSR_PS) ? 1 : 0;
|
||||
env->psret = (val & PSR_ET) ? 1 : 0;
|
||||
#endif
|
||||
env->cc_op = CC_OP_FLAGS;
|
||||
#if !defined(TARGET_SPARC64)
|
||||
cpu_set_cwp(env, val & PSR_CWP);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Called with BQL held */
|
||||
void cpu_put_psr(CPUSPARCState *env, target_ulong val)
|
||||
{
|
||||
cpu_put_psr_raw(env, val);
|
||||
#if !defined(TARGET_SPARC64)
|
||||
// cpu_check_irqs(env);
|
||||
#endif
|
||||
}
|
||||
|
||||
int cpu_cwp_inc(CPUSPARCState *env, int cwp)
|
||||
{
|
||||
if (unlikely(cwp >= env->nwindows)) {
|
||||
cwp -= env->nwindows;
|
||||
}
|
||||
return cwp;
|
||||
}
|
||||
|
||||
int cpu_cwp_dec(CPUSPARCState *env, int cwp)
|
||||
{
|
||||
if (unlikely(cwp < 0)) {
|
||||
cwp += env->nwindows;
|
||||
}
|
||||
return cwp;
|
||||
}
|
||||
|
||||
#ifndef TARGET_SPARC64
|
||||
void helper_rett(CPUSPARCState *env)
|
||||
{
|
||||
unsigned int cwp;
|
||||
|
||||
if (env->psret == 1) {
|
||||
cpu_raise_exception_ra(env, TT_ILL_INSN, GETPC());
|
||||
}
|
||||
|
||||
env->psret = 1;
|
||||
cwp = cpu_cwp_inc(env, env->cwp + 1) ;
|
||||
if (env->wim & (1 << cwp)) {
|
||||
cpu_raise_exception_ra(env, TT_WIN_UNF, GETPC());
|
||||
}
|
||||
cpu_set_cwp(env, cwp);
|
||||
env->psrs = env->psrps;
|
||||
}
|
||||
|
||||
/* XXX: use another pointer for %iN registers to avoid slow wrapping
|
||||
handling ? */
|
||||
void helper_save(CPUSPARCState *env)
|
||||
{
|
||||
uint32_t cwp;
|
||||
|
||||
cwp = cpu_cwp_dec(env, env->cwp - 1);
|
||||
if (env->wim & (1 << cwp)) {
|
||||
cpu_raise_exception_ra(env, TT_WIN_OVF, GETPC());
|
||||
}
|
||||
cpu_set_cwp(env, cwp);
|
||||
}
|
||||
|
||||
void helper_restore(CPUSPARCState *env)
|
||||
{
|
||||
uint32_t cwp;
|
||||
|
||||
cwp = cpu_cwp_inc(env, env->cwp + 1);
|
||||
if (env->wim & (1 << cwp)) {
|
||||
cpu_raise_exception_ra(env, TT_WIN_UNF, GETPC());
|
||||
}
|
||||
cpu_set_cwp(env, cwp);
|
||||
}
|
||||
|
||||
void helper_wrpsr(CPUSPARCState *env, target_ulong new_psr)
|
||||
{
|
||||
if ((new_psr & PSR_CWP) >= env->nwindows) {
|
||||
cpu_raise_exception_ra(env, TT_ILL_INSN, GETPC());
|
||||
} else {
|
||||
/* cpu_put_psr may trigger interrupts, hence BQL */
|
||||
cpu_put_psr(env, new_psr);
|
||||
}
|
||||
}
|
||||
|
||||
target_ulong helper_rdpsr(CPUSPARCState *env)
|
||||
{
|
||||
return cpu_get_psr(env);
|
||||
}
|
||||
|
||||
#else
|
||||
/* XXX: use another pointer for %iN registers to avoid slow wrapping
|
||||
handling ? */
|
||||
void helper_save(CPUSPARCState *env)
|
||||
{
|
||||
uint32_t cwp;
|
||||
|
||||
cwp = cpu_cwp_dec(env, env->cwp - 1);
|
||||
if (env->cansave == 0) {
|
||||
int tt = TT_SPILL | (env->otherwin != 0
|
||||
? (TT_WOTHER | ((env->wstate & 0x38) >> 1))
|
||||
: ((env->wstate & 0x7) << 2));
|
||||
cpu_raise_exception_ra(env, tt, GETPC());
|
||||
} else {
|
||||
if (env->cleanwin - env->canrestore == 0) {
|
||||
/* XXX Clean windows without trap */
|
||||
cpu_raise_exception_ra(env, TT_CLRWIN, GETPC());
|
||||
} else {
|
||||
env->cansave--;
|
||||
env->canrestore++;
|
||||
cpu_set_cwp(env, cwp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void helper_restore(CPUSPARCState *env)
|
||||
{
|
||||
uint32_t cwp;
|
||||
|
||||
cwp = cpu_cwp_inc(env, env->cwp + 1);
|
||||
if (env->canrestore == 0) {
|
||||
int tt = TT_FILL | (env->otherwin != 0
|
||||
? (TT_WOTHER | ((env->wstate & 0x38) >> 1))
|
||||
: ((env->wstate & 0x7) << 2));
|
||||
cpu_raise_exception_ra(env, tt, GETPC());
|
||||
} else {
|
||||
env->cansave++;
|
||||
env->canrestore--;
|
||||
cpu_set_cwp(env, cwp);
|
||||
}
|
||||
}
|
||||
|
||||
void helper_flushw(CPUSPARCState *env)
|
||||
{
|
||||
if (env->cansave != env->nwindows - 2) {
|
||||
int tt = TT_SPILL | (env->otherwin != 0
|
||||
? (TT_WOTHER | ((env->wstate & 0x38) >> 1))
|
||||
: ((env->wstate & 0x7) << 2));
|
||||
cpu_raise_exception_ra(env, tt, GETPC());
|
||||
}
|
||||
}
|
||||
|
||||
void helper_saved(CPUSPARCState *env)
|
||||
{
|
||||
env->cansave++;
|
||||
if (env->otherwin == 0) {
|
||||
env->canrestore--;
|
||||
} else {
|
||||
env->otherwin--;
|
||||
}
|
||||
}
|
||||
|
||||
void helper_restored(CPUSPARCState *env)
|
||||
{
|
||||
env->canrestore++;
|
||||
if (env->cleanwin < env->nwindows - 1) {
|
||||
env->cleanwin++;
|
||||
}
|
||||
if (env->otherwin == 0) {
|
||||
env->cansave--;
|
||||
} else {
|
||||
env->otherwin--;
|
||||
}
|
||||
}
|
||||
|
||||
target_ulong cpu_get_ccr(CPUSPARCState *env)
|
||||
{
|
||||
target_ulong psr;
|
||||
|
||||
psr = cpu_get_psr(env);
|
||||
|
||||
return ((env->xcc >> 20) << 4) | ((psr & PSR_ICC) >> 20);
|
||||
}
|
||||
|
||||
void cpu_put_ccr(CPUSPARCState *env, target_ulong val)
|
||||
{
|
||||
env->xcc = (val >> 4) << 20;
|
||||
env->psr = (val & 0xf) << 20;
|
||||
CC_OP = CC_OP_FLAGS;
|
||||
}
|
||||
|
||||
target_ulong cpu_get_cwp64(CPUSPARCState *env)
|
||||
{
|
||||
return env->nwindows - 1 - env->cwp;
|
||||
}
|
||||
|
||||
void cpu_put_cwp64(CPUSPARCState *env, int cwp)
|
||||
{
|
||||
if (unlikely(cwp >= env->nwindows || cwp < 0)) {
|
||||
cwp %= env->nwindows;
|
||||
}
|
||||
cpu_set_cwp(env, env->nwindows - 1 - cwp);
|
||||
}
|
||||
|
||||
target_ulong helper_rdccr(CPUSPARCState *env)
|
||||
{
|
||||
return cpu_get_ccr(env);
|
||||
}
|
||||
|
||||
void helper_wrccr(CPUSPARCState *env, target_ulong new_ccr)
|
||||
{
|
||||
cpu_put_ccr(env, new_ccr);
|
||||
}
|
||||
|
||||
/* CWP handling is reversed in V9, but we still use the V8 register
|
||||
order. */
|
||||
target_ulong helper_rdcwp(CPUSPARCState *env)
|
||||
{
|
||||
return cpu_get_cwp64(env);
|
||||
}
|
||||
|
||||
void helper_wrcwp(CPUSPARCState *env, target_ulong new_cwp)
|
||||
{
|
||||
cpu_put_cwp64(env, new_cwp);
|
||||
}
|
||||
|
||||
static inline uint64_t *get_gregset(CPUSPARCState *env, uint32_t pstate)
|
||||
{
|
||||
if (env->def.features & CPU_FEATURE_GL) {
|
||||
return env->glregs + (env->gl & 7) * 8;
|
||||
}
|
||||
|
||||
switch (pstate) {
|
||||
default:
|
||||
/* pass through to normal set of global registers */
|
||||
case 0:
|
||||
return env->bgregs;
|
||||
case PS_AG:
|
||||
return env->agregs;
|
||||
case PS_MG:
|
||||
return env->mgregs;
|
||||
case PS_IG:
|
||||
return env->igregs;
|
||||
}
|
||||
}
|
||||
|
||||
static inline uint64_t *get_gl_gregset(CPUSPARCState *env, uint32_t gl)
|
||||
{
|
||||
return env->glregs + (gl & 7) * 8;
|
||||
}
|
||||
|
||||
/* Switch global register bank */
|
||||
void cpu_gl_switch_gregs(CPUSPARCState *env, uint32_t new_gl)
|
||||
{
|
||||
uint64_t *src, *dst;
|
||||
src = get_gl_gregset(env, new_gl);
|
||||
dst = get_gl_gregset(env, env->gl);
|
||||
|
||||
if (src != dst) {
|
||||
memcpy32(dst, env->gregs);
|
||||
memcpy32(env->gregs, src);
|
||||
}
|
||||
}
|
||||
|
||||
void helper_wrgl(CPUSPARCState *env, target_ulong new_gl)
|
||||
{
|
||||
cpu_gl_switch_gregs(env, new_gl & 7);
|
||||
env->gl = new_gl & 7;
|
||||
}
|
||||
|
||||
void cpu_change_pstate(CPUSPARCState *env, uint32_t new_pstate)
|
||||
{
|
||||
uint32_t pstate_regs, new_pstate_regs;
|
||||
uint64_t *src, *dst;
|
||||
|
||||
if (env->def.features & CPU_FEATURE_GL) {
|
||||
/* PS_AG, IG and MG are not implemented in this case */
|
||||
new_pstate &= ~(PS_AG | PS_IG | PS_MG);
|
||||
env->pstate = new_pstate;
|
||||
return;
|
||||
}
|
||||
|
||||
pstate_regs = env->pstate & 0xc01;
|
||||
new_pstate_regs = new_pstate & 0xc01;
|
||||
|
||||
if (new_pstate_regs != pstate_regs) {
|
||||
/* Switch global register bank */
|
||||
src = get_gregset(env, new_pstate_regs);
|
||||
dst = get_gregset(env, pstate_regs);
|
||||
memcpy32(dst, env->gregs);
|
||||
memcpy32(env->gregs, src);
|
||||
}
|
||||
env->pstate = new_pstate;
|
||||
}
|
||||
|
||||
void helper_wrpstate(CPUSPARCState *env, target_ulong new_state)
|
||||
{
|
||||
cpu_change_pstate(env, new_state & 0xf3f);
|
||||
|
||||
if (cpu_interrupts_enabled(env)) {
|
||||
// cpu_check_irqs(env);
|
||||
}
|
||||
}
|
||||
|
||||
void helper_wrpil(CPUSPARCState *env, target_ulong new_pil)
|
||||
{
|
||||
env->psrpil = new_pil;
|
||||
|
||||
if (cpu_interrupts_enabled(env)) {
|
||||
// cpu_check_irqs(env);
|
||||
}
|
||||
}
|
||||
|
||||
void helper_done(CPUSPARCState *env)
|
||||
{
|
||||
trap_state *tsptr = cpu_tsptr(env);
|
||||
|
||||
env->pc = tsptr->tnpc;
|
||||
env->npc = tsptr->tnpc + 4;
|
||||
cpu_put_ccr(env, tsptr->tstate >> 32);
|
||||
env->asi = (tsptr->tstate >> 24) & 0xff;
|
||||
cpu_change_pstate(env, (tsptr->tstate >> 8) & 0xf3f);
|
||||
cpu_put_cwp64(env, tsptr->tstate & 0xff);
|
||||
if (cpu_has_hypervisor(env)) {
|
||||
uint32_t new_gl = (tsptr->tstate >> 40) & 7;
|
||||
env->hpstate = env->htstate[env->tl];
|
||||
cpu_gl_switch_gregs(env, new_gl);
|
||||
env->gl = new_gl;
|
||||
}
|
||||
env->tl--;
|
||||
|
||||
if (cpu_interrupts_enabled(env)) {
|
||||
// cpu_check_irqs(env);
|
||||
}
|
||||
}
|
||||
|
||||
void helper_retry(CPUSPARCState *env)
|
||||
{
|
||||
trap_state *tsptr = cpu_tsptr(env);
|
||||
|
||||
env->pc = tsptr->tpc;
|
||||
env->npc = tsptr->tnpc;
|
||||
cpu_put_ccr(env, tsptr->tstate >> 32);
|
||||
env->asi = (tsptr->tstate >> 24) & 0xff;
|
||||
cpu_change_pstate(env, (tsptr->tstate >> 8) & 0xf3f);
|
||||
cpu_put_cwp64(env, tsptr->tstate & 0xff);
|
||||
if (cpu_has_hypervisor(env)) {
|
||||
uint32_t new_gl = (tsptr->tstate >> 40) & 7;
|
||||
env->hpstate = env->htstate[env->tl];
|
||||
cpu_gl_switch_gregs(env, new_gl);
|
||||
env->gl = new_gl;
|
||||
}
|
||||
env->tl--;
|
||||
|
||||
if (cpu_interrupts_enabled(env)) {
|
||||
// cpu_check_irqs(env);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user