mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-03 07:43:54 -06:00
Move target-* CPU file into a target/ folder
We've currently got 18 architectures in QEMU, and thus 18 target-xxx folders in the root folder of the QEMU source tree. More architectures (e.g. RISC-V, AVR) are likely to be included soon, too, so the main folder of the QEMU sources slowly gets quite overcrowded with the target-xxx folders. To disburden the main folder a little bit, let's move the target-xxx folders into a dedicated target/ folder, so that target-xxx/ simply becomes target/xxx/ instead. Acked-by: Laurent Vivier <laurent@vivier.eu> [m68k part] Acked-by: Bastian Koppelmann <kbastian@mail.uni-paderborn.de> [tricore part] Acked-by: Michael Walle <michael@walle.cc> [lm32 part] Acked-by: Cornelia Huck <cornelia.huck@de.ibm.com> [s390x part] Reviewed-by: Christian Borntraeger <borntraeger@de.ibm.com> [s390x part] Acked-by: Eduardo Habkost <ehabkost@redhat.com> [i386 part] Acked-by: Artyom Tarasenko <atar4qemu@gmail.com> [sparc part] Acked-by: Richard Henderson <rth@twiddle.net> [alpha part] Acked-by: Max Filippov <jcmvbkbc@gmail.com> [xtensa part] Reviewed-by: David Gibson <david@gibson.dropbear.id.au> [ppc part] Acked-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com> [crisµblaze part] Acked-by: Guan Xuetao <gxt@mprc.pku.edu.cn> [unicore32 part] Signed-off-by: Thomas Huth <thuth@redhat.com>
This commit is contained in:
parent
82ecffa8c0
commit
fcf5ef2ab5
369 changed files with 78 additions and 80 deletions
7
target/sparc/Makefile.objs
Normal file
7
target/sparc/Makefile.objs
Normal file
|
@ -0,0 +1,7 @@
|
|||
obj-$(CONFIG_SOFTMMU) += machine.o monitor.o
|
||||
obj-y += translate.o helper.o cpu.o
|
||||
obj-y += fop_helper.o cc_helper.o win_helper.o mmu_helper.o ldst_helper.o
|
||||
obj-$(TARGET_SPARC) += int32_helper.o
|
||||
obj-$(TARGET_SPARC64) += int64_helper.o
|
||||
obj-$(TARGET_SPARC64) += vis_helper.o
|
||||
obj-y += gdbstub.o
|
88
target/sparc/TODO
Normal file
88
target/sparc/TODO
Normal file
|
@ -0,0 +1,88 @@
|
|||
TODO-list:
|
||||
|
||||
CPU common:
|
||||
- Unimplemented features/bugs:
|
||||
- Delay slot handling may fail sometimes (branch end of page, delay
|
||||
slot next page)
|
||||
- Atomical instructions
|
||||
- CPU features should match real CPUs (also ASI selection)
|
||||
- Optimizations/improvements:
|
||||
- Condition code/branch handling like x86, also for FPU?
|
||||
- Remove remaining explicit alignment checks
|
||||
- Global register for regwptr, so that windowed registers can be
|
||||
accessed directly
|
||||
- Improve Sparc32plus addressing
|
||||
- NPC/PC static optimisations (use JUMP_TB when possible)? (Is this
|
||||
obsolete?)
|
||||
- Synthetic instructions
|
||||
- MMU model dependent on CPU model
|
||||
- Select ASI helper at translation time (on V9 only if known)
|
||||
- KQemu/KVM support for VM only
|
||||
- Hardware breakpoint/watchpoint support
|
||||
- Cache emulation mode
|
||||
- Reverse-endian pages
|
||||
- Faster FPU emulation
|
||||
- Busy loop detection
|
||||
|
||||
Sparc32 CPUs:
|
||||
- Unimplemented features/bugs:
|
||||
- Sun4/Sun4c MMUs
|
||||
- Some V8 ASIs
|
||||
|
||||
Sparc64 CPUs:
|
||||
- Unimplemented features/bugs:
|
||||
- Interrupt handling
|
||||
- Secondary address space, other MMU functions
|
||||
- Many V9/UA2005/UA2007 ASIs
|
||||
- Rest of V9 instructions, missing VIS instructions
|
||||
- IG/MG/AG vs. UA2007 globals
|
||||
- Full hypervisor support
|
||||
- SMP/CMT
|
||||
- Sun4v CPUs
|
||||
|
||||
Sun4:
|
||||
- To be added
|
||||
|
||||
Sun4c:
|
||||
- A lot of unimplemented features
|
||||
- Maybe split from Sun4m
|
||||
|
||||
Sun4m:
|
||||
- Unimplemented features/bugs:
|
||||
- Hardware devices do not match real boards
|
||||
- Floppy does not work
|
||||
- CS4231: merge with cs4231a, add DMA
|
||||
- Add cg6, bwtwo
|
||||
- Arbitrary resolution support
|
||||
- PCI for MicroSparc-IIe
|
||||
- JavaStation machines
|
||||
- SBus slot probing, FCode ROM support
|
||||
- SMP probing support
|
||||
- Interrupt routing does not match real HW
|
||||
- SuSE 7.3 keyboard sometimes unresponsive
|
||||
- Gentoo 2004.1 SMP does not work
|
||||
- SS600MP ledma -> lebuffer
|
||||
- Type 5 keyboard
|
||||
- Less fixed hardware choices
|
||||
- DBRI audio (Am7930)
|
||||
- BPP parallel
|
||||
- Diagnostic switch
|
||||
- ESP PIO mode
|
||||
|
||||
Sun4d:
|
||||
- A lot of unimplemented features:
|
||||
- SBI
|
||||
- IO-unit
|
||||
- Maybe split from Sun4m
|
||||
|
||||
Sun4u:
|
||||
- Unimplemented features/bugs:
|
||||
- Interrupt controller
|
||||
- PCI/IOMMU support (Simba, JIO, Tomatillo, Psycho, Schizo, Safari...)
|
||||
- SMP
|
||||
- Happy Meal Ethernet, flash, I2C, GPIO
|
||||
- A lot of real machine types
|
||||
|
||||
Sun4v:
|
||||
- A lot of unimplemented features
|
||||
- A lot of real machine types
|
311
target/sparc/asi.h
Normal file
311
target/sparc/asi.h
Normal file
|
@ -0,0 +1,311 @@
|
|||
#ifndef _SPARC_ASI_H
|
||||
#define _SPARC_ASI_H
|
||||
|
||||
/* asi.h: Address Space Identifier values for the sparc.
|
||||
*
|
||||
* Copyright (C) 1995,1996 David S. Miller (davem@caip.rutgers.edu)
|
||||
*
|
||||
* Pioneer work for sun4m: Paul Hatchman (paul@sfe.com.au)
|
||||
* Joint edition for sun4c+sun4m: Pete A. Zaitcev <zaitcev@ipmce.su>
|
||||
*/
|
||||
|
||||
/* The first batch are for the sun4c. */
|
||||
|
||||
#define ASI_NULL1 0x00
|
||||
#define ASI_NULL2 0x01
|
||||
|
||||
/* sun4c and sun4 control registers and mmu/vac ops */
|
||||
#define ASI_CONTROL 0x02
|
||||
#define ASI_SEGMAP 0x03
|
||||
#define ASI_PTE 0x04
|
||||
#define ASI_HWFLUSHSEG 0x05
|
||||
#define ASI_HWFLUSHPAGE 0x06
|
||||
#define ASI_REGMAP 0x06
|
||||
#define ASI_HWFLUSHCONTEXT 0x07
|
||||
|
||||
#define ASI_USERTXT 0x08
|
||||
#define ASI_KERNELTXT 0x09
|
||||
#define ASI_USERDATA 0x0a
|
||||
#define ASI_KERNELDATA 0x0b
|
||||
|
||||
/* VAC Cache flushing on sun4c and sun4 */
|
||||
#define ASI_FLUSHSEG 0x0c
|
||||
#define ASI_FLUSHPG 0x0d
|
||||
#define ASI_FLUSHCTX 0x0e
|
||||
|
||||
/* SPARCstation-5: only 6 bits are decoded. */
|
||||
/* wo = Write Only, rw = Read Write; */
|
||||
/* ss = Single Size, as = All Sizes; */
|
||||
#define ASI_M_RES00 0x00 /* Don't touch... */
|
||||
#define ASI_M_UNA01 0x01 /* Same here... */
|
||||
#define ASI_M_MXCC 0x02 /* Access to TI VIKING MXCC registers */
|
||||
#define ASI_M_FLUSH_PROBE 0x03 /* Reference MMU Flush/Probe; rw, ss */
|
||||
#define ASI_M_MMUREGS 0x04 /* MMU Registers; rw, ss */
|
||||
#define ASI_M_TLBDIAG 0x05 /* MMU TLB only Diagnostics */
|
||||
#define ASI_M_DIAGS 0x06 /* Reference MMU Diagnostics */
|
||||
#define ASI_M_IODIAG 0x07 /* MMU I/O TLB only Diagnostics */
|
||||
#define ASI_M_USERTXT 0x08 /* Same as ASI_USERTXT; rw, as */
|
||||
#define ASI_M_KERNELTXT 0x09 /* Same as ASI_KERNELTXT; rw, as */
|
||||
#define ASI_M_USERDATA 0x0A /* Same as ASI_USERDATA; rw, as */
|
||||
#define ASI_M_KERNELDATA 0x0B /* Same as ASI_KERNELDATA; rw, as */
|
||||
#define ASI_M_TXTC_TAG 0x0C /* Instruction Cache Tag; rw, ss */
|
||||
#define ASI_M_TXTC_DATA 0x0D /* Instruction Cache Data; rw, ss */
|
||||
#define ASI_M_DATAC_TAG 0x0E /* Data Cache Tag; rw, ss */
|
||||
#define ASI_M_DATAC_DATA 0x0F /* Data Cache Data; rw, ss */
|
||||
|
||||
/* The following cache flushing ASIs work only with the 'sta'
|
||||
* instruction. Results are unpredictable for 'swap' and 'ldstuba',
|
||||
* so don't do it.
|
||||
*/
|
||||
|
||||
/* These ASI flushes affect external caches too. */
|
||||
#define ASI_M_FLUSH_PAGE 0x10 /* Flush I&D Cache Line (page); wo, ss */
|
||||
#define ASI_M_FLUSH_SEG 0x11 /* Flush I&D Cache Line (seg); wo, ss */
|
||||
#define ASI_M_FLUSH_REGION 0x12 /* Flush I&D Cache Line (region); wo, ss */
|
||||
#define ASI_M_FLUSH_CTX 0x13 /* Flush I&D Cache Line (context); wo, ss */
|
||||
#define ASI_M_FLUSH_USER 0x14 /* Flush I&D Cache Line (user); wo, ss */
|
||||
|
||||
/* Block-copy operations are available only on certain V8 cpus. */
|
||||
#define ASI_M_BCOPY 0x17 /* Block copy */
|
||||
|
||||
/* These affect only the ICACHE and are Ross HyperSparc and TurboSparc specific. */
|
||||
#define ASI_M_IFLUSH_PAGE 0x18 /* Flush I Cache Line (page); wo, ss */
|
||||
#define ASI_M_IFLUSH_SEG 0x19 /* Flush I Cache Line (seg); wo, ss */
|
||||
#define ASI_M_IFLUSH_REGION 0x1A /* Flush I Cache Line (region); wo, ss */
|
||||
#define ASI_M_IFLUSH_CTX 0x1B /* Flush I Cache Line (context); wo, ss */
|
||||
#define ASI_M_IFLUSH_USER 0x1C /* Flush I Cache Line (user); wo, ss */
|
||||
|
||||
/* Block-fill operations are available on certain V8 cpus */
|
||||
#define ASI_M_BFILL 0x1F
|
||||
|
||||
/* This allows direct access to main memory, actually 0x20 to 0x2f are
|
||||
* the available ASI's for physical ram pass-through, but I don't have
|
||||
* any idea what the other ones do....
|
||||
*/
|
||||
|
||||
#define ASI_M_BYPASS 0x20 /* Reference MMU bypass; rw, as */
|
||||
#define ASI_M_FBMEM 0x29 /* Graphics card frame buffer access */
|
||||
#define ASI_M_VMEUS 0x2A /* VME user 16-bit access */
|
||||
#define ASI_M_VMEPS 0x2B /* VME priv 16-bit access */
|
||||
#define ASI_M_VMEUT 0x2C /* VME user 32-bit access */
|
||||
#define ASI_M_VMEPT 0x2D /* VME priv 32-bit access */
|
||||
#define ASI_M_SBUS 0x2E /* Direct SBus access */
|
||||
#define ASI_M_CTL 0x2F /* Control Space (ECC and MXCC are here) */
|
||||
|
||||
|
||||
/* This is ROSS HyperSparc only. */
|
||||
#define ASI_M_FLUSH_IWHOLE 0x31 /* Flush entire ICACHE; wo, ss */
|
||||
|
||||
/* Tsunami/Viking/TurboSparc i/d cache flash clear. */
|
||||
#define ASI_M_IC_FLCLEAR 0x36
|
||||
#define ASI_M_DC_FLCLEAR 0x37
|
||||
|
||||
#define ASI_M_DCDR 0x39 /* Data Cache Diagnostics Register rw, ss */
|
||||
|
||||
#define ASI_M_VIKING_TMP1 0x40 /* Emulation temporary 1 on Viking */
|
||||
/* only available on SuperSparc I */
|
||||
/* #define ASI_M_VIKING_TMP2 0x41 */ /* Emulation temporary 2 on Viking */
|
||||
|
||||
#define ASI_M_ACTION 0x4c /* Breakpoint Action Register (GNU/Viking) */
|
||||
|
||||
/* LEON ASI */
|
||||
#define ASI_LEON_NOCACHE 0x01
|
||||
|
||||
#define ASI_LEON_DCACHE_MISS 0x01
|
||||
|
||||
#define ASI_LEON_CACHEREGS 0x02
|
||||
#define ASI_LEON_IFLUSH 0x10
|
||||
#define ASI_LEON_DFLUSH 0x11
|
||||
|
||||
#define ASI_LEON_MMUFLUSH 0x18
|
||||
#define ASI_LEON_MMUREGS 0x19
|
||||
#define ASI_LEON_BYPASS 0x1c
|
||||
#define ASI_LEON_FLUSH_PAGE 0x10
|
||||
|
||||
/* V9 Architecture mandary ASIs. */
|
||||
#define ASI_N 0x04 /* Nucleus */
|
||||
#define ASI_NL 0x0c /* Nucleus, little endian */
|
||||
#define ASI_AIUP 0x10 /* Primary, user */
|
||||
#define ASI_AIUS 0x11 /* Secondary, user */
|
||||
#define ASI_AIUPL 0x18 /* Primary, user, little endian */
|
||||
#define ASI_AIUSL 0x19 /* Secondary, user, little endian */
|
||||
#define ASI_P 0x80 /* Primary, implicit */
|
||||
#define ASI_S 0x81 /* Secondary, implicit */
|
||||
#define ASI_PNF 0x82 /* Primary, no fault */
|
||||
#define ASI_SNF 0x83 /* Secondary, no fault */
|
||||
#define ASI_PL 0x88 /* Primary, implicit, l-endian */
|
||||
#define ASI_SL 0x89 /* Secondary, implicit, l-endian */
|
||||
#define ASI_PNFL 0x8a /* Primary, no fault, l-endian */
|
||||
#define ASI_SNFL 0x8b /* Secondary, no fault, l-endian */
|
||||
|
||||
/* SpitFire and later extended ASIs. The "(III)" marker designates
|
||||
* UltraSparc-III and later specific ASIs. The "(CMT)" marker designates
|
||||
* Chip Multi Threading specific ASIs. "(NG)" designates Niagara specific
|
||||
* ASIs, "(4V)" designates SUN4V specific ASIs. "(NG4)" designates SPARC-T4
|
||||
* and later ASIs.
|
||||
*/
|
||||
#define ASI_REAL 0x14 /* Real address, cachable */
|
||||
#define ASI_PHYS_USE_EC 0x14 /* PADDR, E-cachable */
|
||||
#define ASI_REAL_IO 0x15 /* Real address, non-cachable */
|
||||
#define ASI_PHYS_BYPASS_EC_E 0x15 /* PADDR, E-bit */
|
||||
#define ASI_BLK_AIUP_4V 0x16 /* (4V) Prim, user, block ld/st */
|
||||
#define ASI_BLK_AIUS_4V 0x17 /* (4V) Sec, user, block ld/st */
|
||||
#define ASI_REAL_L 0x1c /* Real address, cachable, LE */
|
||||
#define ASI_PHYS_USE_EC_L 0x1c /* PADDR, E-cachable, little endian*/
|
||||
#define ASI_REAL_IO_L 0x1d /* Real address, non-cachable, LE */
|
||||
#define ASI_PHYS_BYPASS_EC_E_L 0x1d /* PADDR, E-bit, little endian */
|
||||
#define ASI_BLK_AIUP_L_4V 0x1e /* (4V) Prim, user, block, l-endian*/
|
||||
#define ASI_BLK_AIUS_L_4V 0x1f /* (4V) Sec, user, block, l-endian */
|
||||
#define ASI_SCRATCHPAD 0x20 /* (4V) Scratch Pad Registers */
|
||||
#define ASI_MMU 0x21 /* (4V) MMU Context Registers */
|
||||
#define ASI_TWINX_AIUP 0x22 /* twin load, primary user */
|
||||
#define ASI_TWINX_AIUS 0x23 /* twin load, secondary user */
|
||||
#define ASI_BLK_INIT_QUAD_LDD_AIUS 0x23 /* (NG) init-store, twin load,
|
||||
* secondary, user
|
||||
*/
|
||||
#define ASI_NUCLEUS_QUAD_LDD 0x24 /* Cachable, qword load */
|
||||
#define ASI_QUEUE 0x25 /* (4V) Interrupt Queue Registers */
|
||||
#define ASI_TWINX_REAL 0x26 /* twin load, real, cachable */
|
||||
#define ASI_QUAD_LDD_PHYS_4V 0x26 /* (4V) Physical, qword load */
|
||||
#define ASI_TWINX_N 0x27 /* twin load, nucleus */
|
||||
#define ASI_TWINX_AIUP_L 0x2a /* twin load, primary user, LE */
|
||||
#define ASI_TWINX_AIUS_L 0x2b /* twin load, secondary user, LE */
|
||||
#define ASI_NUCLEUS_QUAD_LDD_L 0x2c /* Cachable, qword load, l-endian */
|
||||
#define ASI_TWINX_REAL_L 0x2e /* twin load, real, cachable, LE */
|
||||
#define ASI_QUAD_LDD_PHYS_L_4V 0x2e /* (4V) Phys, qword load, l-endian */
|
||||
#define ASI_TWINX_NL 0x2f /* twin load, nucleus, LE */
|
||||
#define ASI_PCACHE_DATA_STATUS 0x30 /* (III) PCache data stat RAM diag */
|
||||
#define ASI_PCACHE_DATA 0x31 /* (III) PCache data RAM diag */
|
||||
#define ASI_PCACHE_TAG 0x32 /* (III) PCache tag RAM diag */
|
||||
#define ASI_PCACHE_SNOOP_TAG 0x33 /* (III) PCache snoop tag RAM diag */
|
||||
#define ASI_QUAD_LDD_PHYS 0x34 /* (III+) PADDR, qword load */
|
||||
#define ASI_WCACHE_VALID_BITS 0x38 /* (III) WCache Valid Bits diag */
|
||||
#define ASI_WCACHE_DATA 0x39 /* (III) WCache data RAM diag */
|
||||
#define ASI_WCACHE_TAG 0x3a /* (III) WCache tag RAM diag */
|
||||
#define ASI_WCACHE_SNOOP_TAG 0x3b /* (III) WCache snoop tag RAM diag */
|
||||
#define ASI_QUAD_LDD_PHYS_L 0x3c /* (III+) PADDR, qw-load, l-endian */
|
||||
#define ASI_SRAM_FAST_INIT 0x40 /* (III+) Fast SRAM init */
|
||||
#define ASI_CORE_AVAILABLE 0x41 /* (CMT) LP Available */
|
||||
#define ASI_CORE_ENABLE_STAT 0x41 /* (CMT) LP Enable Status */
|
||||
#define ASI_CORE_ENABLE 0x41 /* (CMT) LP Enable RW */
|
||||
#define ASI_XIR_STEERING 0x41 /* (CMT) XIR Steering RW */
|
||||
#define ASI_CORE_RUNNING_RW 0x41 /* (CMT) LP Running RW */
|
||||
#define ASI_CORE_RUNNING_W1S 0x41 /* (CMT) LP Running Write-One Set */
|
||||
#define ASI_CORE_RUNNING_W1C 0x41 /* (CMT) LP Running Write-One Clr */
|
||||
#define ASI_CORE_RUNNING_STAT 0x41 /* (CMT) LP Running Status */
|
||||
#define ASI_CMT_ERROR_STEERING 0x41 /* (CMT) Error Steering RW */
|
||||
#define ASI_DCACHE_INVALIDATE 0x42 /* (III) DCache Invalidate diag */
|
||||
#define ASI_DCACHE_UTAG 0x43 /* (III) DCache uTag diag */
|
||||
#define ASI_DCACHE_SNOOP_TAG 0x44 /* (III) DCache snoop tag RAM diag */
|
||||
#define ASI_LSU_CONTROL 0x45 /* Load-store control unit */
|
||||
#define ASI_DCU_CONTROL_REG 0x45 /* (III) DCache Unit Control reg */
|
||||
#define ASI_DCACHE_DATA 0x46 /* DCache data-ram diag access */
|
||||
#define ASI_DCACHE_TAG 0x47 /* Dcache tag/valid ram diag access*/
|
||||
#define ASI_INTR_DISPATCH_STAT 0x48 /* IRQ vector dispatch status */
|
||||
#define ASI_INTR_RECEIVE 0x49 /* IRQ vector receive status */
|
||||
#define ASI_UPA_CONFIG 0x4a /* UPA config space */
|
||||
#define ASI_JBUS_CONFIG 0x4a /* (IIIi) JBUS Config Register */
|
||||
#define ASI_SAFARI_CONFIG 0x4a /* (III) Safari Config Register */
|
||||
#define ASI_SAFARI_ADDRESS 0x4a /* (III) Safari Address Register */
|
||||
#define ASI_ESTATE_ERROR_EN 0x4b /* E-cache error enable space */
|
||||
#define ASI_AFSR 0x4c /* Async fault status register */
|
||||
#define ASI_AFAR 0x4d /* Async fault address register */
|
||||
#define ASI_EC_TAG_DATA 0x4e /* E-cache tag/valid ram diag acc */
|
||||
#define ASI_IMMU 0x50 /* Insn-MMU main register space */
|
||||
#define ASI_IMMU_TSB_8KB_PTR 0x51 /* Insn-MMU 8KB TSB pointer reg */
|
||||
#define ASI_IMMU_TSB_64KB_PTR 0x52 /* Insn-MMU 64KB TSB pointer reg */
|
||||
#define ASI_ITLB_DATA_IN 0x54 /* Insn-MMU TLB data in reg */
|
||||
#define ASI_ITLB_DATA_ACCESS 0x55 /* Insn-MMU TLB data access reg */
|
||||
#define ASI_ITLB_TAG_READ 0x56 /* Insn-MMU TLB tag read reg */
|
||||
#define ASI_IMMU_DEMAP 0x57 /* Insn-MMU TLB demap */
|
||||
#define ASI_DMMU 0x58 /* Data-MMU main register space */
|
||||
#define ASI_DMMU_TSB_8KB_PTR 0x59 /* Data-MMU 8KB TSB pointer reg */
|
||||
#define ASI_DMMU_TSB_64KB_PTR 0x5a /* Data-MMU 16KB TSB pointer reg */
|
||||
#define ASI_DMMU_TSB_DIRECT_PTR 0x5b /* Data-MMU TSB direct pointer reg */
|
||||
#define ASI_DTLB_DATA_IN 0x5c /* Data-MMU TLB data in reg */
|
||||
#define ASI_DTLB_DATA_ACCESS 0x5d /* Data-MMU TLB data access reg */
|
||||
#define ASI_DTLB_TAG_READ 0x5e /* Data-MMU TLB tag read reg */
|
||||
#define ASI_DMMU_DEMAP 0x5f /* Data-MMU TLB demap */
|
||||
#define ASI_IIU_INST_TRAP 0x60 /* (III) Instruction Breakpoint */
|
||||
#define ASI_INTR_ID 0x63 /* (CMT) Interrupt ID register */
|
||||
#define ASI_CORE_ID 0x63 /* (CMT) LP ID register */
|
||||
#define ASI_CESR_ID 0x63 /* (CMT) CESR ID register */
|
||||
#define ASI_IC_INSTR 0x66 /* Insn cache instrucion ram diag */
|
||||
#define ASI_IC_TAG 0x67 /* Insn cache tag/valid ram diag */
|
||||
#define ASI_IC_STAG 0x68 /* (III) Insn cache snoop tag ram */
|
||||
#define ASI_IC_PRE_DECODE 0x6e /* Insn cache pre-decode ram diag */
|
||||
#define ASI_IC_NEXT_FIELD 0x6f /* Insn cache next-field ram diag */
|
||||
#define ASI_BRPRED_ARRAY 0x6f /* (III) Branch Prediction RAM diag*/
|
||||
#define ASI_BLK_AIUP 0x70 /* Primary, user, block load/store */
|
||||
#define ASI_BLK_AIUS 0x71 /* Secondary, user, block ld/st */
|
||||
#define ASI_MCU_CTRL_REG 0x72 /* (III) Memory controller regs */
|
||||
#define ASI_EC_DATA 0x74 /* (III) E-cache data staging reg */
|
||||
#define ASI_EC_CTRL 0x75 /* (III) E-cache control reg */
|
||||
#define ASI_EC_W 0x76 /* E-cache diag write access */
|
||||
#define ASI_UDB_ERROR_W 0x77 /* External UDB error regs W */
|
||||
#define ASI_UDB_CONTROL_W 0x77 /* External UDB control regs W */
|
||||
#define ASI_INTR_W 0x77 /* IRQ vector dispatch write */
|
||||
#define ASI_INTR_DATAN_W 0x77 /* (III) Out irq vector data reg N */
|
||||
#define ASI_INTR_DISPATCH_W 0x77 /* (III) Interrupt vector dispatch */
|
||||
#define ASI_BLK_AIUPL 0x78 /* Primary, user, little, blk ld/st*/
|
||||
#define ASI_BLK_AIUSL 0x79 /* Secondary, user, little, blk ld/st*/
|
||||
#define ASI_EC_R 0x7e /* E-cache diag read access */
|
||||
#define ASI_UDBH_ERROR_R 0x7f /* External UDB error regs rd hi */
|
||||
#define ASI_UDBL_ERROR_R 0x7f /* External UDB error regs rd low */
|
||||
#define ASI_UDBH_CONTROL_R 0x7f /* External UDB control regs rd hi */
|
||||
#define ASI_UDBL_CONTROL_R 0x7f /* External UDB control regs rd low*/
|
||||
#define ASI_INTR_R 0x7f /* IRQ vector dispatch read */
|
||||
#define ASI_INTR_DATAN_R 0x7f /* (III) In irq vector data reg N */
|
||||
#define ASI_PIC 0xb0 /* (NG4) PIC registers */
|
||||
#define ASI_PST8_P 0xc0 /* Primary, 8 8-bit, partial */
|
||||
#define ASI_PST8_S 0xc1 /* Secondary, 8 8-bit, partial */
|
||||
#define ASI_PST16_P 0xc2 /* Primary, 4 16-bit, partial */
|
||||
#define ASI_PST16_S 0xc3 /* Secondary, 4 16-bit, partial */
|
||||
#define ASI_PST32_P 0xc4 /* Primary, 2 32-bit, partial */
|
||||
#define ASI_PST32_S 0xc5 /* Secondary, 2 32-bit, partial */
|
||||
#define ASI_PST8_PL 0xc8 /* Primary, 8 8-bit, partial, L */
|
||||
#define ASI_PST8_SL 0xc9 /* Secondary, 8 8-bit, partial, L */
|
||||
#define ASI_PST16_PL 0xca /* Primary, 4 16-bit, partial, L */
|
||||
#define ASI_PST16_SL 0xcb /* Secondary, 4 16-bit, partial, L */
|
||||
#define ASI_PST32_PL 0xcc /* Primary, 2 32-bit, partial, L */
|
||||
#define ASI_PST32_SL 0xcd /* Secondary, 2 32-bit, partial, L */
|
||||
#define ASI_FL8_P 0xd0 /* Primary, 1 8-bit, fpu ld/st */
|
||||
#define ASI_FL8_S 0xd1 /* Secondary, 1 8-bit, fpu ld/st */
|
||||
#define ASI_FL16_P 0xd2 /* Primary, 1 16-bit, fpu ld/st */
|
||||
#define ASI_FL16_S 0xd3 /* Secondary, 1 16-bit, fpu ld/st */
|
||||
#define ASI_FL8_PL 0xd8 /* Primary, 1 8-bit, fpu ld/st, L */
|
||||
#define ASI_FL8_SL 0xd9 /* Secondary, 1 8-bit, fpu ld/st, L*/
|
||||
#define ASI_FL16_PL 0xda /* Primary, 1 16-bit, fpu ld/st, L */
|
||||
#define ASI_FL16_SL 0xdb /* Secondary, 1 16-bit, fpu ld/st,L*/
|
||||
#define ASI_BLK_COMMIT_P 0xe0 /* Primary, blk store commit */
|
||||
#define ASI_BLK_COMMIT_S 0xe1 /* Secondary, blk store commit */
|
||||
#define ASI_TWINX_P 0xe2 /* twin load, primary implicit */
|
||||
#define ASI_BLK_INIT_QUAD_LDD_P 0xe2 /* (NG) init-store, twin load,
|
||||
* primary, implicit */
|
||||
#define ASI_TWINX_S 0xe3 /* twin load, secondary implicit */
|
||||
#define ASI_BLK_INIT_QUAD_LDD_S 0xe3 /* (NG) init-store, twin load,
|
||||
* secondary, implicit */
|
||||
#define ASI_TWINX_PL 0xea /* twin load, primary implicit, LE */
|
||||
#define ASI_TWINX_SL 0xeb /* twin load, secondary implicit, LE */
|
||||
#define ASI_BLK_P 0xf0 /* Primary, blk ld/st */
|
||||
#define ASI_BLK_S 0xf1 /* Secondary, blk ld/st */
|
||||
#define ASI_ST_BLKINIT_MRU_P 0xf2 /* (NG4) init-store, twin load,
|
||||
* Most-Recently-Used, primary,
|
||||
* implicit
|
||||
*/
|
||||
#define ASI_ST_BLKINIT_MRU_S 0xf2 /* (NG4) init-store, twin load,
|
||||
* Most-Recently-Used, secondary,
|
||||
* implicit
|
||||
*/
|
||||
#define ASI_BLK_PL 0xf8 /* Primary, blk ld/st, little */
|
||||
#define ASI_BLK_SL 0xf9 /* Secondary, blk ld/st, little */
|
||||
#define ASI_ST_BLKINIT_MRU_PL 0xfa /* (NG4) init-store, twin load,
|
||||
* Most-Recently-Used, primary,
|
||||
* implicit, little-endian
|
||||
*/
|
||||
#define ASI_ST_BLKINIT_MRU_SL 0xfb /* (NG4) init-store, twin load,
|
||||
* Most-Recently-Used, secondary,
|
||||
* implicit, little-endian
|
||||
*/
|
||||
|
||||
#endif /* _SPARC_ASI_H */
|
471
target/sparc/cc_helper.c
Normal file
471
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;
|
||||
}
|
56
target/sparc/cpu-qom.h
Normal file
56
target/sparc/cpu-qom.h
Normal file
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* 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 "qom/cpu.h"
|
||||
|
||||
#ifdef TARGET_SPARC64
|
||||
#define TYPE_SPARC_CPU "sparc64-cpu"
|
||||
#else
|
||||
#define TYPE_SPARC_CPU "sparc-cpu"
|
||||
#endif
|
||||
|
||||
#define SPARC_CPU_CLASS(klass) \
|
||||
OBJECT_CLASS_CHECK(SPARCCPUClass, (klass), TYPE_SPARC_CPU)
|
||||
#define SPARC_CPU(obj) \
|
||||
OBJECT_CHECK(SPARCCPU, (obj), TYPE_SPARC_CPU)
|
||||
#define SPARC_CPU_GET_CLASS(obj) \
|
||||
OBJECT_GET_CLASS(SPARCCPUClass, (obj), TYPE_SPARC_CPU)
|
||||
|
||||
/**
|
||||
* 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 >*/
|
||||
|
||||
DeviceRealize parent_realize;
|
||||
void (*parent_reset)(CPUState *cpu);
|
||||
} SPARCCPUClass;
|
||||
|
||||
typedef struct SPARCCPU SPARCCPU;
|
||||
|
||||
#endif
|
895
target/sparc/cpu.c
Normal file
895
target/sparc/cpu.c
Normal file
|
@ -0,0 +1,895 @@
|
|||
/*
|
||||
* 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 "qapi/error.h"
|
||||
#include "cpu.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "exec/exec-all.h"
|
||||
|
||||
//#define DEBUG_FEATURES
|
||||
|
||||
static int cpu_sparc_find_by_name(sparc_def_t *cpu_def, const char *cpu_model);
|
||||
|
||||
/* CPUClass::reset() */
|
||||
static void sparc_cpu_reset(CPUState *s)
|
||||
{
|
||||
SPARCCPU *cpu = SPARC_CPU(s);
|
||||
SPARCCPUClass *scc = SPARC_CPU_GET_CLASS(cpu);
|
||||
CPUSPARCState *env = &cpu->env;
|
||||
|
||||
scc->parent_reset(s);
|
||||
|
||||
memset(env, 0, offsetof(CPUSPARCState, version));
|
||||
tlb_flush(s, 1);
|
||||
env->cwp = 0;
|
||||
#ifndef TARGET_SPARC64
|
||||
env->wim = 1;
|
||||
#endif
|
||||
env->regwptr = env->regbase + (env->cwp * 16);
|
||||
CC_OP = CC_OP_FLAGS;
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
#ifdef TARGET_SPARC64
|
||||
env->cleanwin = env->nwindows - 2;
|
||||
env->cansave = env->nwindows - 2;
|
||||
env->pstate = PS_RMO | PS_PEF | PS_IE;
|
||||
env->asi = 0x82; /* Primary no-fault */
|
||||
#endif
|
||||
#else
|
||||
#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|PS_AG;
|
||||
env->hpstate = cpu_has_hypervisor(env) ? HS_PRIV : 0;
|
||||
env->tl = env->maxtl;
|
||||
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;
|
||||
#endif
|
||||
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;
|
||||
}
|
||||
|
||||
static void cpu_sparc_disas_set_info(CPUState *cpu, disassemble_info *info)
|
||||
{
|
||||
info->print_insn = print_insn_sparc;
|
||||
#ifdef TARGET_SPARC64
|
||||
info->mach = bfd_mach_sparc_v9b;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void sparc_cpu_parse_features(CPUState *cs, char *features,
|
||||
Error **errp);
|
||||
|
||||
static int cpu_sparc_register(SPARCCPU *cpu, const char *cpu_model)
|
||||
{
|
||||
CPUSPARCState *env = &cpu->env;
|
||||
char *s = g_strdup(cpu_model);
|
||||
char *featurestr, *name = strtok(s, ",");
|
||||
sparc_def_t def1, *def = &def1;
|
||||
Error *err = NULL;
|
||||
|
||||
if (cpu_sparc_find_by_name(def, name) < 0) {
|
||||
g_free(s);
|
||||
return -1;
|
||||
}
|
||||
|
||||
env->def = g_memdup(def, sizeof(*def));
|
||||
|
||||
featurestr = strtok(NULL, ",");
|
||||
sparc_cpu_parse_features(CPU(cpu), featurestr, &err);
|
||||
g_free(s);
|
||||
if (err) {
|
||||
error_report_err(err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
env->version = def->iu_version;
|
||||
env->fsr = def->fpu_version;
|
||||
env->nwindows = def->nwindows;
|
||||
#if !defined(TARGET_SPARC64)
|
||||
env->mmuregs[0] |= def->mmu_version;
|
||||
cpu_sparc_set_id(env, 0);
|
||||
env->mxccregs[7] |= def->mxcc_version;
|
||||
#else
|
||||
env->mmu_version = def->mmu_version;
|
||||
env->maxtl = def->maxtl;
|
||||
env->version |= def->maxtl << 8;
|
||||
env->version |= def->nwindows - 1;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
SPARCCPU *cpu_sparc_init(const char *cpu_model)
|
||||
{
|
||||
SPARCCPU *cpu;
|
||||
|
||||
cpu = SPARC_CPU(object_new(TYPE_SPARC_CPU));
|
||||
|
||||
if (cpu_sparc_register(cpu, cpu_model) < 0) {
|
||||
object_unref(OBJECT(cpu));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
object_property_set_bool(OBJECT(cpu), true, "realized", NULL);
|
||||
|
||||
return cpu;
|
||||
}
|
||||
|
||||
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 const char * const feature_name[] = {
|
||||
"float",
|
||||
"float128",
|
||||
"swap",
|
||||
"mul",
|
||||
"div",
|
||||
"flush",
|
||||
"fsqrt",
|
||||
"fmul",
|
||||
"vis1",
|
||||
"vis2",
|
||||
"fsmuld",
|
||||
"hypv",
|
||||
"cmt",
|
||||
"gl",
|
||||
};
|
||||
|
||||
static void print_features(FILE *f, fprintf_function cpu_fprintf,
|
||||
uint32_t features, const char *prefix)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(feature_name); i++) {
|
||||
if (feature_name[i] && (features & (1 << i))) {
|
||||
if (prefix) {
|
||||
(*cpu_fprintf)(f, "%s", prefix);
|
||||
}
|
||||
(*cpu_fprintf)(f, "%s ", feature_name[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void add_flagname_to_bitmaps(const char *flagname, uint32_t *features)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(feature_name); i++) {
|
||||
if (feature_name[i] && !strcmp(flagname, feature_name[i])) {
|
||||
*features |= 1 << i;
|
||||
return;
|
||||
}
|
||||
}
|
||||
error_report("CPU feature %s not found", flagname);
|
||||
}
|
||||
|
||||
static int cpu_sparc_find_by_name(sparc_def_t *cpu_def, const char *name)
|
||||
{
|
||||
unsigned int i;
|
||||
const sparc_def_t *def = NULL;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(sparc_defs); i++) {
|
||||
if (strcasecmp(name, sparc_defs[i].name) == 0) {
|
||||
def = &sparc_defs[i];
|
||||
}
|
||||
}
|
||||
if (!def) {
|
||||
return -1;
|
||||
}
|
||||
memcpy(cpu_def, def, sizeof(*def));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sparc_cpu_parse_features(CPUState *cs, char *features,
|
||||
Error **errp)
|
||||
{
|
||||
SPARCCPU *cpu = SPARC_CPU(cs);
|
||||
sparc_def_t *cpu_def = cpu->env.def;
|
||||
char *featurestr;
|
||||
uint32_t plus_features = 0;
|
||||
uint32_t minus_features = 0;
|
||||
uint64_t iu_version;
|
||||
uint32_t fpu_version, mmu_version, nwindows;
|
||||
|
||||
featurestr = features ? strtok(features, ",") : NULL;
|
||||
while (featurestr) {
|
||||
char *val;
|
||||
|
||||
if (featurestr[0] == '+') {
|
||||
add_flagname_to_bitmaps(featurestr + 1, &plus_features);
|
||||
} else if (featurestr[0] == '-') {
|
||||
add_flagname_to_bitmaps(featurestr + 1, &minus_features);
|
||||
} else if ((val = strchr(featurestr, '='))) {
|
||||
*val = 0; val++;
|
||||
if (!strcmp(featurestr, "iu_version")) {
|
||||
char *err;
|
||||
|
||||
iu_version = strtoll(val, &err, 0);
|
||||
if (!*val || *err) {
|
||||
error_setg(errp, "bad numerical value %s", val);
|
||||
return;
|
||||
}
|
||||
cpu_def->iu_version = iu_version;
|
||||
#ifdef DEBUG_FEATURES
|
||||
fprintf(stderr, "iu_version %" PRIx64 "\n", iu_version);
|
||||
#endif
|
||||
} else if (!strcmp(featurestr, "fpu_version")) {
|
||||
char *err;
|
||||
|
||||
fpu_version = strtol(val, &err, 0);
|
||||
if (!*val || *err) {
|
||||
error_setg(errp, "bad numerical value %s", val);
|
||||
return;
|
||||
}
|
||||
cpu_def->fpu_version = fpu_version;
|
||||
#ifdef DEBUG_FEATURES
|
||||
fprintf(stderr, "fpu_version %x\n", fpu_version);
|
||||
#endif
|
||||
} else if (!strcmp(featurestr, "mmu_version")) {
|
||||
char *err;
|
||||
|
||||
mmu_version = strtol(val, &err, 0);
|
||||
if (!*val || *err) {
|
||||
error_setg(errp, "bad numerical value %s", val);
|
||||
return;
|
||||
}
|
||||
cpu_def->mmu_version = mmu_version;
|
||||
#ifdef DEBUG_FEATURES
|
||||
fprintf(stderr, "mmu_version %x\n", mmu_version);
|
||||
#endif
|
||||
} else if (!strcmp(featurestr, "nwindows")) {
|
||||
char *err;
|
||||
|
||||
nwindows = strtol(val, &err, 0);
|
||||
if (!*val || *err || nwindows > MAX_NWINDOWS ||
|
||||
nwindows < MIN_NWINDOWS) {
|
||||
error_setg(errp, "bad numerical value %s", val);
|
||||
return;
|
||||
}
|
||||
cpu_def->nwindows = nwindows;
|
||||
#ifdef DEBUG_FEATURES
|
||||
fprintf(stderr, "nwindows %d\n", nwindows);
|
||||
#endif
|
||||
} else {
|
||||
error_setg(errp, "unrecognized feature %s", featurestr);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
error_setg(errp, "feature string `%s' not in format "
|
||||
"(+feature|-feature|feature=xyz)", featurestr);
|
||||
return;
|
||||
}
|
||||
featurestr = strtok(NULL, ",");
|
||||
}
|
||||
cpu_def->features |= plus_features;
|
||||
cpu_def->features &= ~minus_features;
|
||||
#ifdef DEBUG_FEATURES
|
||||
print_features(stderr, fprintf, cpu_def->features, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
void sparc_cpu_list(FILE *f, fprintf_function cpu_fprintf)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(sparc_defs); i++) {
|
||||
(*cpu_fprintf)(f, "Sparc %16s IU " TARGET_FMT_lx
|
||||
" FPU %08x MMU %08x NWINS %d ",
|
||||
sparc_defs[i].name,
|
||||
sparc_defs[i].iu_version,
|
||||
sparc_defs[i].fpu_version,
|
||||
sparc_defs[i].mmu_version,
|
||||
sparc_defs[i].nwindows);
|
||||
print_features(f, cpu_fprintf, CPU_DEFAULT_FEATURES &
|
||||
~sparc_defs[i].features, "-");
|
||||
print_features(f, cpu_fprintf, ~CPU_DEFAULT_FEATURES &
|
||||
sparc_defs[i].features, "+");
|
||||
(*cpu_fprintf)(f, "\n");
|
||||
}
|
||||
(*cpu_fprintf)(f, "Default CPU feature flags (use '-' to remove): ");
|
||||
print_features(f, cpu_fprintf, CPU_DEFAULT_FEATURES, NULL);
|
||||
(*cpu_fprintf)(f, "\n");
|
||||
(*cpu_fprintf)(f, "Available CPU feature flags (use '+' to add): ");
|
||||
print_features(f, cpu_fprintf, ~CPU_DEFAULT_FEATURES, NULL);
|
||||
(*cpu_fprintf)(f, "\n");
|
||||
(*cpu_fprintf)(f, "Numerical features (use '=' to set): iu_version "
|
||||
"fpu_version mmu_version nwindows\n");
|
||||
}
|
||||
|
||||
static void cpu_print_cc(FILE *f, fprintf_function cpu_fprintf,
|
||||
uint32_t cc)
|
||||
{
|
||||
cpu_fprintf(f, "%c%c%c%c", cc & PSR_NEG ? 'N' : '-',
|
||||
cc & PSR_ZERO ? 'Z' : '-', cc & PSR_OVF ? 'V' : '-',
|
||||
cc & PSR_CARRY ? 'C' : '-');
|
||||
}
|
||||
|
||||
#ifdef TARGET_SPARC64
|
||||
#define REGS_PER_LINE 4
|
||||
#else
|
||||
#define REGS_PER_LINE 8
|
||||
#endif
|
||||
|
||||
void sparc_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
|
||||
int flags)
|
||||
{
|
||||
SPARCCPU *cpu = SPARC_CPU(cs);
|
||||
CPUSPARCState *env = &cpu->env;
|
||||
int i, x;
|
||||
|
||||
cpu_fprintf(f, "pc: " TARGET_FMT_lx " npc: " TARGET_FMT_lx "\n", env->pc,
|
||||
env->npc);
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (i % REGS_PER_LINE == 0) {
|
||||
cpu_fprintf(f, "%%g%d-%d:", i, i + REGS_PER_LINE - 1);
|
||||
}
|
||||
cpu_fprintf(f, " " TARGET_FMT_lx, env->gregs[i]);
|
||||
if (i % REGS_PER_LINE == REGS_PER_LINE - 1) {
|
||||
cpu_fprintf(f, "\n");
|
||||
}
|
||||
}
|
||||
for (x = 0; x < 3; x++) {
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (i % REGS_PER_LINE == 0) {
|
||||
cpu_fprintf(f, "%%%c%d-%d: ",
|
||||
x == 0 ? 'o' : (x == 1 ? 'l' : 'i'),
|
||||
i, i + REGS_PER_LINE - 1);
|
||||
}
|
||||
cpu_fprintf(f, TARGET_FMT_lx " ", env->regwptr[i + x * 8]);
|
||||
if (i % REGS_PER_LINE == REGS_PER_LINE - 1) {
|
||||
cpu_fprintf(f, "\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < TARGET_DPREGS; i++) {
|
||||
if ((i & 3) == 0) {
|
||||
cpu_fprintf(f, "%%f%02d: ", i * 2);
|
||||
}
|
||||
cpu_fprintf(f, " %016" PRIx64, env->fpr[i].ll);
|
||||
if ((i & 3) == 3) {
|
||||
cpu_fprintf(f, "\n");
|
||||
}
|
||||
}
|
||||
#ifdef TARGET_SPARC64
|
||||
cpu_fprintf(f, "pstate: %08x ccr: %02x (icc: ", env->pstate,
|
||||
(unsigned)cpu_get_ccr(env));
|
||||
cpu_print_cc(f, cpu_fprintf, cpu_get_ccr(env) << PSR_CARRY_SHIFT);
|
||||
cpu_fprintf(f, " xcc: ");
|
||||
cpu_print_cc(f, cpu_fprintf, cpu_get_ccr(env) << (PSR_CARRY_SHIFT - 4));
|
||||
cpu_fprintf(f, ") asi: %02x tl: %d pil: %x\n", env->asi, env->tl,
|
||||
env->psrpil);
|
||||
cpu_fprintf(f, "cansave: %d canrestore: %d otherwin: %d wstate: %d "
|
||||
"cleanwin: %d cwp: %d\n",
|
||||
env->cansave, env->canrestore, env->otherwin, env->wstate,
|
||||
env->cleanwin, env->nwindows - 1 - env->cwp);
|
||||
cpu_fprintf(f, "fsr: " TARGET_FMT_lx " y: " TARGET_FMT_lx " fprs: "
|
||||
TARGET_FMT_lx "\n", env->fsr, env->y, env->fprs);
|
||||
#else
|
||||
cpu_fprintf(f, "psr: %08x (icc: ", cpu_get_psr(env));
|
||||
cpu_print_cc(f, cpu_fprintf, cpu_get_psr(env));
|
||||
cpu_fprintf(f, " SPE: %c%c%c) wim: %08x\n", env->psrs ? 'S' : '-',
|
||||
env->psrps ? 'P' : '-', env->psret ? 'E' : '-',
|
||||
env->wim);
|
||||
cpu_fprintf(f, "fsr: " TARGET_FMT_lx " y: " TARGET_FMT_lx "\n",
|
||||
env->fsr, env->y);
|
||||
#endif
|
||||
cpu_fprintf(f, "\n");
|
||||
}
|
||||
|
||||
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(DeviceState *dev, Error **errp)
|
||||
{
|
||||
CPUState *cs = CPU(dev);
|
||||
SPARCCPUClass *scc = SPARC_CPU_GET_CLASS(dev);
|
||||
Error *local_err = NULL;
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
SPARCCPU *cpu = SPARC_CPU(dev);
|
||||
CPUSPARCState *env = &cpu->env;
|
||||
|
||||
if ((env->def->features & CPU_FEATURE_FLOAT)) {
|
||||
env->def->features |= CPU_FEATURE_FLOAT128;
|
||||
}
|
||||
#endif
|
||||
|
||||
cpu_exec_realizefn(cs, &local_err);
|
||||
if (local_err != NULL) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
|
||||
qemu_init_vcpu(cs);
|
||||
|
||||
scc->parent_realize(dev, errp);
|
||||
}
|
||||
|
||||
static void sparc_cpu_initfn(Object *obj)
|
||||
{
|
||||
CPUState *cs = CPU(obj);
|
||||
SPARCCPU *cpu = SPARC_CPU(obj);
|
||||
CPUSPARCState *env = &cpu->env;
|
||||
|
||||
cs->env_ptr = env;
|
||||
|
||||
if (tcg_enabled()) {
|
||||
gen_intermediate_code_init(env);
|
||||
}
|
||||
}
|
||||
|
||||
static void sparc_cpu_uninitfn(Object *obj)
|
||||
{
|
||||
SPARCCPU *cpu = SPARC_CPU(obj);
|
||||
CPUSPARCState *env = &cpu->env;
|
||||
|
||||
g_free(env->def);
|
||||
}
|
||||
|
||||
static void sparc_cpu_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
SPARCCPUClass *scc = SPARC_CPU_CLASS(oc);
|
||||
CPUClass *cc = CPU_CLASS(oc);
|
||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||
|
||||
scc->parent_realize = dc->realize;
|
||||
dc->realize = sparc_cpu_realizefn;
|
||||
|
||||
scc->parent_reset = cc->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->dump_state = sparc_cpu_dump_state;
|
||||
#if !defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY)
|
||||
cc->memory_rw_debug = sparc_cpu_memory_rw_debug;
|
||||
#endif
|
||||
cc->set_pc = sparc_cpu_set_pc;
|
||||
cc->synchronize_from_tb = sparc_cpu_synchronize_from_tb;
|
||||
cc->gdb_read_register = sparc_cpu_gdb_read_register;
|
||||
cc->gdb_write_register = sparc_cpu_gdb_write_register;
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
cc->handle_mmu_fault = sparc_cpu_handle_mmu_fault;
|
||||
#else
|
||||
cc->do_unassigned_access = sparc_cpu_unassigned_access;
|
||||
cc->do_unaligned_access = sparc_cpu_do_unaligned_access;
|
||||
cc->get_phys_page_debug = sparc_cpu_get_phys_page_debug;
|
||||
cc->vmsd = &vmstate_sparc_cpu;
|
||||
#endif
|
||||
cc->disas_set_info = cpu_sparc_disas_set_info;
|
||||
|
||||
#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
|
||||
cc->gdb_num_core_regs = 86;
|
||||
#else
|
||||
cc->gdb_num_core_regs = 72;
|
||||
#endif
|
||||
}
|
||||
|
||||
static const TypeInfo sparc_cpu_type_info = {
|
||||
.name = TYPE_SPARC_CPU,
|
||||
.parent = TYPE_CPU,
|
||||
.instance_size = sizeof(SPARCCPU),
|
||||
.instance_init = sparc_cpu_initfn,
|
||||
.instance_finalize = sparc_cpu_uninitfn,
|
||||
.abstract = false,
|
||||
.class_size = sizeof(SPARCCPUClass),
|
||||
.class_init = sparc_cpu_class_init,
|
||||
};
|
||||
|
||||
static void sparc_cpu_register_types(void)
|
||||
{
|
||||
type_register_static(&sparc_cpu_type_info);
|
||||
}
|
||||
|
||||
type_init(sparc_cpu_register_types)
|
779
target/sparc/cpu.h
Normal file
779
target/sparc/cpu.h
Normal file
|
@ -0,0 +1,779 @@
|
|||
#ifndef SPARC_CPU_H
|
||||
#define SPARC_CPU_H
|
||||
|
||||
#include "qemu-common.h"
|
||||
#include "qemu/bswap.h"
|
||||
#include "cpu-qom.h"
|
||||
|
||||
#define ALIGNED_ONLY
|
||||
|
||||
#if !defined(TARGET_SPARC64)
|
||||
#define TARGET_LONG_BITS 32
|
||||
#define TARGET_DPREGS 16
|
||||
#define TARGET_PAGE_BITS 12 /* 4k */
|
||||
#define TARGET_PHYS_ADDR_SPACE_BITS 36
|
||||
#define TARGET_VIRT_ADDR_SPACE_BITS 32
|
||||
#else
|
||||
#define TARGET_LONG_BITS 64
|
||||
#define TARGET_DPREGS 32
|
||||
#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
|
||||
#endif
|
||||
|
||||
#define CPUArchState struct CPUSPARCState
|
||||
|
||||
#include "exec/cpu-defs.h"
|
||||
|
||||
#include "fpu/softfloat.h"
|
||||
|
||||
/*#define EXCP_INTERRUPT 0x100*/
|
||||
|
||||
/* 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_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
|
||||
#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
|
||||
|
||||
#if !defined(TARGET_SPARC64)
|
||||
#define NB_MMU_MODES 3
|
||||
#else
|
||||
#define NB_MMU_MODES 7
|
||||
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
|
||||
|
||||
typedef 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;
|
||||
} sparc_def_t;
|
||||
|
||||
#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_USED_BIT (1ULL << 41)
|
||||
#define TTE_LOCKED_BIT (1ULL << 6)
|
||||
#define TTE_SIDEEFFECT_BIT (1ULL << 3)
|
||||
#define TTE_PRIV_BIT (1ULL << 2)
|
||||
#define TTE_W_OK_BIT (1ULL << 1)
|
||||
#define TTE_GLOBAL_BIT (1ULL << 0)
|
||||
|
||||
#define TTE_IS_VALID(tte) ((tte) & TTE_VALID_BIT)
|
||||
#define TTE_IS_NFO(tte) ((tte) & TTE_NFO_BIT)
|
||||
#define TTE_IS_USED(tte) ((tte) & TTE_USED_BIT)
|
||||
#define TTE_IS_LOCKED(tte) ((tte) & TTE_LOCKED_BIT)
|
||||
#define TTE_IS_SIDEEFFECT(tte) ((tte) & TTE_SIDEEFFECT_BIT)
|
||||
#define TTE_IS_PRIV(tte) ((tte) & TTE_PRIV_BIT)
|
||||
#define TTE_IS_W_OK(tte) ((tte) & TTE_W_OK_BIT)
|
||||
#define TTE_IS_GLOBAL(tte) ((tte) & TTE_GLOBAL_BIT)
|
||||
|
||||
#define TTE_SET_USED(tte) ((tte) |= TTE_USED_BIT)
|
||||
#define TTE_SET_UNUSED(tte) ((tte) &= ~TTE_USED_BIT)
|
||||
|
||||
#define TTE_PGSIZE(tte) (((tte) >> 61) & 3ULL)
|
||||
#define TTE_PA(tte) ((tte) & 0x1ffffffe000ULL)
|
||||
|
||||
#define SFSR_NF_BIT (1ULL << 24) /* JPS1 NoFault */
|
||||
#define SFSR_TM_BIT (1ULL << 15) /* JPS1 TLB Miss */
|
||||
#define SFSR_FT_VA_IMMU_BIT (1ULL << 13) /* USIIi VA out of range (IMMU) */
|
||||
#define SFSR_FT_VA_DMMU_BIT (1ULL << 12) /* USIIi VA out of range (DMMU) */
|
||||
#define SFSR_FT_NFO_BIT (1ULL << 11) /* NFO page access */
|
||||
#define SFSR_FT_ILL_BIT (1ULL << 10) /* illegal LDA/STA ASI */
|
||||
#define SFSR_FT_ATOMIC_BIT (1ULL << 9) /* atomic op on noncacheable area */
|
||||
#define SFSR_FT_NF_E_BIT (1ULL << 8) /* NF access on side effect area */
|
||||
#define SFSR_FT_PRIV_BIT (1ULL << 7) /* privilege violation */
|
||||
#define SFSR_PR_BIT (1ULL << 3) /* privilege mode */
|
||||
#define SFSR_WRITE_BIT (1ULL << 2) /* write access mode */
|
||||
#define SFSR_OW_BIT (1ULL << 1) /* status overwritten */
|
||||
#define SFSR_VALID_BIT (1ULL << 0) /* status valid */
|
||||
|
||||
#define SFSR_ASI_SHIFT 16 /* 23:16 ASI value */
|
||||
#define SFSR_ASI_MASK (0xffULL << SFSR_ASI_SHIFT)
|
||||
#define SFSR_CT_PRIMARY (0ULL << 4) /* 5:4 context type */
|
||||
#define SFSR_CT_SECONDARY (1ULL << 4)
|
||||
#define SFSR_CT_NUCLEUS (2ULL << 4)
|
||||
#define SFSR_CT_NOTRANS (3ULL << 4)
|
||||
#define SFSR_CT_MASK (3ULL << 4)
|
||||
|
||||
/* 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 */
|
||||
|
||||
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;
|
||||
|
||||
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];
|
||||
|
||||
CPU_COMMON
|
||||
|
||||
/* 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
|
||||
//typedef struct SparcMMU
|
||||
union {
|
||||
uint64_t immuregs[16];
|
||||
struct {
|
||||
uint64_t tsb_tag_target;
|
||||
uint64_t unused_mmu_primary_context; // use DMMU
|
||||
uint64_t unused_mmu_secondary_context; // use DMMU
|
||||
uint64_t sfsr;
|
||||
uint64_t sfar;
|
||||
uint64_t tsb;
|
||||
uint64_t tag_access;
|
||||
} immu;
|
||||
};
|
||||
union {
|
||||
uint64_t dmmuregs[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;
|
||||
} 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 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;
|
||||
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;
|
||||
|
||||
void *irq_manager;
|
||||
void (*qemu_irq_ack)(CPUSPARCState *env, void *irq_manager, int intno);
|
||||
|
||||
/* Leon3 cache control */
|
||||
uint32_t cache_control;
|
||||
};
|
||||
|
||||
/**
|
||||
* SPARCCPU:
|
||||
* @env: #CPUSPARCState
|
||||
*
|
||||
* A SPARC CPU.
|
||||
*/
|
||||
struct SPARCCPU {
|
||||
/*< private >*/
|
||||
CPUState parent_obj;
|
||||
/*< public >*/
|
||||
|
||||
CPUSPARCState env;
|
||||
};
|
||||
|
||||
static inline SPARCCPU *sparc_env_get_cpu(CPUSPARCState *env)
|
||||
{
|
||||
return container_of(env, SPARCCPU, env);
|
||||
}
|
||||
|
||||
#define ENV_GET_CPU(e) CPU(sparc_env_get_cpu(e))
|
||||
|
||||
#define ENV_OFFSET offsetof(SPARCCPU, env)
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
extern const struct VMStateDescription vmstate_sparc_cpu;
|
||||
#endif
|
||||
|
||||
void sparc_cpu_do_interrupt(CPUState *cpu);
|
||||
void sparc_cpu_dump_state(CPUState *cpu, FILE *f,
|
||||
fprintf_function cpu_fprintf, int flags);
|
||||
hwaddr sparc_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
|
||||
int sparc_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
|
||||
int sparc_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
|
||||
void QEMU_NORETURN sparc_cpu_do_unaligned_access(CPUState *cpu, vaddr addr,
|
||||
MMUAccessType access_type,
|
||||
int mmu_idx,
|
||||
uintptr_t retaddr);
|
||||
void cpu_raise_exception_ra(CPUSPARCState *, int, uintptr_t) QEMU_NORETURN;
|
||||
|
||||
#ifndef NO_CPU_IO_DEFS
|
||||
/* cpu_init.c */
|
||||
SPARCCPU *cpu_sparc_init(const char *cpu_model);
|
||||
void cpu_sparc_set_id(CPUSPARCState *env, unsigned int cpu);
|
||||
void sparc_cpu_list(FILE *f, fprintf_function cpu_fprintf);
|
||||
/* mmu_helper.c */
|
||||
int sparc_cpu_handle_mmu_fault(CPUState *cpu, vaddr address, int rw,
|
||||
int mmu_idx);
|
||||
target_ulong mmu_probe(CPUSPARCState *env, target_ulong address, int mmulev);
|
||||
void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUSPARCState *env);
|
||||
|
||||
#if !defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY)
|
||||
int sparc_cpu_memory_rw_debug(CPUState *cpu, vaddr addr,
|
||||
uint8_t *buf, int len, bool is_write);
|
||||
#endif
|
||||
|
||||
|
||||
/* translate.c */
|
||||
void gen_intermediate_code_init(CPUSPARCState *env);
|
||||
|
||||
/* 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);
|
||||
#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);
|
||||
|
||||
/* sun4m.c, sun4u.c */
|
||||
void cpu_check_irqs(CPUSPARCState *env);
|
||||
|
||||
/* 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 */
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
void sparc_cpu_unassigned_access(CPUState *cpu, hwaddr addr,
|
||||
bool is_write, bool is_exec, int is_asi,
|
||||
unsigned size);
|
||||
#if defined(TARGET_SPARC64)
|
||||
hwaddr cpu_get_phys_page_nofault(CPUSPARCState *env, target_ulong addr,
|
||||
int mmu_idx);
|
||||
#endif
|
||||
#endif
|
||||
int cpu_sparc_signal_handler(int host_signum, void *pinfo, void *puc);
|
||||
|
||||
#ifndef NO_CPU_IO_DEFS
|
||||
#define cpu_init(cpu_model) CPU(cpu_sparc_init(cpu_model))
|
||||
#endif
|
||||
|
||||
#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_HYPV_IDX 5
|
||||
#define MMU_PHYS_IDX 6
|
||||
#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;
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline int cpu_mmu_index(CPUSPARCState *env, bool ifetch)
|
||||
{
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
return MMU_USER_IDX;
|
||||
#elif !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 (env->tl > 0) {
|
||||
return MMU_NUCLEUS_IDX;
|
||||
} else if (cpu_hypervisor_mode(env)) {
|
||||
return MMU_HYPV_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)
|
||||
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
|
||||
}
|
||||
|
||||
#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_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);
|
||||
#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)
|
||||
{
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
return true;
|
||||
#else
|
||||
return tb_flags & TB_FLAG_FPU_ENABLED;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline bool tb_am_enabled(int tb_flags)
|
||||
{
|
||||
#ifndef TARGET_SPARC64
|
||||
return false;
|
||||
#else
|
||||
return tb_flags & TB_FLAG_AM_ENABLED;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
400
target/sparc/fop_helper.c
Normal file
400
target/sparc/fop_helper.c
Normal file
|
@ -0,0 +1,400 @@
|
|||
/*
|
||||
* 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"
|
||||
|
||||
#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 = CPU(sparc_env_get_cpu(env));
|
||||
|
||||
/* Unmasked exception, generate a trap. Note that while
|
||||
the helper is marked as NO_WG, we can get away with
|
||||
writing to cpu state along the exception path, since
|
||||
TCG generated code will never see the write. */
|
||||
env->fsr = fsr | FSR_FTT_IEEE_EXCP;
|
||||
cs->exception_index = TT_FP_EXCP;
|
||||
cpu_loop_exit_restore(cs, ra);
|
||||
} else {
|
||||
/* Accumulate exceptions */
|
||||
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
|
209
target/sparc/gdbstub.c
Normal file
209
target/sparc/gdbstub.c
Normal file
|
@ -0,0 +1,209 @@
|
|||
/*
|
||||
* SPARC gdb server stub
|
||||
*
|
||||
* Copyright (c) 2003-2005 Fabrice Bellard
|
||||
* Copyright (c) 2013 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 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 "qemu-common.h"
|
||||
#include "cpu.h"
|
||||
#include "exec/gdbstub.h"
|
||||
|
||||
#ifdef TARGET_ABI32
|
||||
#define gdb_get_rega(buf, val) gdb_get_reg32(buf, val)
|
||||
#else
|
||||
#define gdb_get_rega(buf, val) gdb_get_regl(buf, val)
|
||||
#endif
|
||||
|
||||
int sparc_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
|
||||
{
|
||||
SPARCCPU *cpu = SPARC_CPU(cs);
|
||||
CPUSPARCState *env = &cpu->env;
|
||||
|
||||
if (n < 8) {
|
||||
/* g0..g7 */
|
||||
return gdb_get_rega(mem_buf, env->gregs[n]);
|
||||
}
|
||||
if (n < 32) {
|
||||
/* register window */
|
||||
return gdb_get_rega(mem_buf, env->regwptr[n - 8]);
|
||||
}
|
||||
#if defined(TARGET_ABI32) || !defined(TARGET_SPARC64)
|
||||
if (n < 64) {
|
||||
/* fprs */
|
||||
if (n & 1) {
|
||||
return gdb_get_reg32(mem_buf, env->fpr[(n - 32) / 2].l.lower);
|
||||
} else {
|
||||
return gdb_get_reg32(mem_buf, env->fpr[(n - 32) / 2].l.upper);
|
||||
}
|
||||
}
|
||||
/* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
|
||||
switch (n) {
|
||||
case 64:
|
||||
return gdb_get_rega(mem_buf, env->y);
|
||||
case 65:
|
||||
return gdb_get_rega(mem_buf, cpu_get_psr(env));
|
||||
case 66:
|
||||
return gdb_get_rega(mem_buf, env->wim);
|
||||
case 67:
|
||||
return gdb_get_rega(mem_buf, env->tbr);
|
||||
case 68:
|
||||
return gdb_get_rega(mem_buf, env->pc);
|
||||
case 69:
|
||||
return gdb_get_rega(mem_buf, env->npc);
|
||||
case 70:
|
||||
return gdb_get_rega(mem_buf, env->fsr);
|
||||
case 71:
|
||||
return gdb_get_rega(mem_buf, 0); /* csr */
|
||||
default:
|
||||
return gdb_get_rega(mem_buf, 0);
|
||||
}
|
||||
#else
|
||||
if (n < 64) {
|
||||
/* f0-f31 */
|
||||
if (n & 1) {
|
||||
return gdb_get_reg32(mem_buf, env->fpr[(n - 32) / 2].l.lower);
|
||||
} else {
|
||||
return gdb_get_reg32(mem_buf, env->fpr[(n - 32) / 2].l.upper);
|
||||
}
|
||||
}
|
||||
if (n < 80) {
|
||||
/* f32-f62 (double width, even numbers only) */
|
||||
return gdb_get_reg64(mem_buf, env->fpr[(n - 32) / 2].ll);
|
||||
}
|
||||
switch (n) {
|
||||
case 80:
|
||||
return gdb_get_regl(mem_buf, env->pc);
|
||||
case 81:
|
||||
return gdb_get_regl(mem_buf, env->npc);
|
||||
case 82:
|
||||
return gdb_get_regl(mem_buf, (cpu_get_ccr(env) << 32) |
|
||||
((env->asi & 0xff) << 24) |
|
||||
((env->pstate & 0xfff) << 8) |
|
||||
cpu_get_cwp64(env));
|
||||
case 83:
|
||||
return gdb_get_regl(mem_buf, env->fsr);
|
||||
case 84:
|
||||
return gdb_get_regl(mem_buf, env->fprs);
|
||||
case 85:
|
||||
return gdb_get_regl(mem_buf, env->y);
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sparc_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
|
||||
{
|
||||
SPARCCPU *cpu = SPARC_CPU(cs);
|
||||
CPUSPARCState *env = &cpu->env;
|
||||
#if defined(TARGET_ABI32)
|
||||
abi_ulong tmp;
|
||||
|
||||
tmp = ldl_p(mem_buf);
|
||||
#else
|
||||
target_ulong tmp;
|
||||
|
||||
tmp = ldtul_p(mem_buf);
|
||||
#endif
|
||||
|
||||
if (n < 8) {
|
||||
/* g0..g7 */
|
||||
env->gregs[n] = tmp;
|
||||
} else if (n < 32) {
|
||||
/* register window */
|
||||
env->regwptr[n - 8] = tmp;
|
||||
}
|
||||
#if defined(TARGET_ABI32) || !defined(TARGET_SPARC64)
|
||||
else if (n < 64) {
|
||||
/* fprs */
|
||||
/* f0-f31 */
|
||||
if (n & 1) {
|
||||
env->fpr[(n - 32) / 2].l.lower = tmp;
|
||||
} else {
|
||||
env->fpr[(n - 32) / 2].l.upper = tmp;
|
||||
}
|
||||
} else {
|
||||
/* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
|
||||
switch (n) {
|
||||
case 64:
|
||||
env->y = tmp;
|
||||
break;
|
||||
case 65:
|
||||
cpu_put_psr(env, tmp);
|
||||
break;
|
||||
case 66:
|
||||
env->wim = tmp;
|
||||
break;
|
||||
case 67:
|
||||
env->tbr = tmp;
|
||||
break;
|
||||
case 68:
|
||||
env->pc = tmp;
|
||||
break;
|
||||
case 69:
|
||||
env->npc = tmp;
|
||||
break;
|
||||
case 70:
|
||||
env->fsr = tmp;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 4;
|
||||
#else
|
||||
else if (n < 64) {
|
||||
/* f0-f31 */
|
||||
tmp = ldl_p(mem_buf);
|
||||
if (n & 1) {
|
||||
env->fpr[(n - 32) / 2].l.lower = tmp;
|
||||
} else {
|
||||
env->fpr[(n - 32) / 2].l.upper = tmp;
|
||||
}
|
||||
return 4;
|
||||
} else if (n < 80) {
|
||||
/* f32-f62 (double width, even numbers only) */
|
||||
env->fpr[(n - 32) / 2].ll = tmp;
|
||||
} else {
|
||||
switch (n) {
|
||||
case 80:
|
||||
env->pc = tmp;
|
||||
break;
|
||||
case 81:
|
||||
env->npc = tmp;
|
||||
break;
|
||||
case 82:
|
||||
cpu_put_ccr(env, tmp >> 32);
|
||||
env->asi = (tmp >> 24) & 0xff;
|
||||
env->pstate = (tmp >> 8) & 0xfff;
|
||||
cpu_put_cwp64(env, tmp & 0xff);
|
||||
break;
|
||||
case 83:
|
||||
env->fsr = tmp;
|
||||
break;
|
||||
case 84:
|
||||
env->fprs = tmp;
|
||||
break;
|
||||
case 85:
|
||||
env->y = tmp;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 8;
|
||||
#endif
|
||||
}
|
257
target/sparc/helper.c
Normal file
257
target/sparc/helper.c
Normal file
|
@ -0,0 +1,257 @@
|
|||
/*
|
||||
* 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"
|
||||
#include "sysemu/sysemu.h"
|
||||
|
||||
void cpu_raise_exception_ra(CPUSPARCState *env, int tt, uintptr_t ra)
|
||||
{
|
||||
CPUState *cs = CPU(sparc_env_get_cpu(env));
|
||||
|
||||
cs->exception_index = tt;
|
||||
cpu_loop_exit_restore(cs, ra);
|
||||
}
|
||||
|
||||
void helper_raise_exception(CPUSPARCState *env, int tt)
|
||||
{
|
||||
CPUState *cs = CPU(sparc_env_get_cpu(env));
|
||||
|
||||
cs->exception_index = tt;
|
||||
cpu_loop_exit(cs);
|
||||
}
|
||||
|
||||
void helper_debug(CPUSPARCState *env)
|
||||
{
|
||||
CPUState *cs = CPU(sparc_env_get_cpu(env));
|
||||
|
||||
cs->exception_index = EXCP_DEBUG;
|
||||
cpu_loop_exit(cs);
|
||||
}
|
||||
|
||||
#ifdef TARGET_SPARC64
|
||||
target_ulong helper_popc(target_ulong val)
|
||||
{
|
||||
return ctpop64(val);
|
||||
}
|
||||
|
||||
void helper_tick_set_count(void *opaque, uint64_t count)
|
||||
{
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
cpu_tick_set_count(opaque, count);
|
||||
#endif
|
||||
}
|
||||
|
||||
uint64_t helper_tick_get_count(CPUSPARCState *env, void *opaque, int mem_idx)
|
||||
{
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
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);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void helper_tick_set_limit(void *opaque, uint64_t limit)
|
||||
{
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
cpu_tick_set_limit(opaque, limit);
|
||||
#endif
|
||||
}
|
||||
#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 = CPU(sparc_env_get_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
target/sparc/helper.h
Normal file
168
target/sparc/helper.h
Normal file
|
@ -0,0 +1,168 @@
|
|||
#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(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_1(popc, TCG_CALL_NO_RWG_SE, 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
|
||||
#if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64)
|
||||
DEF_HELPER_FLAGS_4(ld_asi, TCG_CALL_NO_WG, i64, env, tl, int, i32)
|
||||
DEF_HELPER_FLAGS_5(st_asi, TCG_CALL_NO_WG, void, env, tl, i64, int, i32)
|
||||
#endif
|
||||
DEF_HELPER_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)
|
175
target/sparc/int32_helper.c
Normal file
175
target/sparc/int32_helper.c
Normal file
|
@ -0,0 +1,175 @@
|
|||
/*
|
||||
* 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 "trace.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "exec/log.h"
|
||||
|
||||
#define DEBUG_PCALL
|
||||
|
||||
#ifdef DEBUG_PCALL
|
||||
static const char * const excp_names[0x80] = {
|
||||
[TT_TFAULT] = "Instruction Access Fault",
|
||||
[TT_ILL_INSN] = "Illegal Instruction",
|
||||
[TT_PRIV_INSN] = "Privileged Instruction",
|
||||
[TT_NFPU_INSN] = "FPU Disabled",
|
||||
[TT_WIN_OVF] = "Window Overflow",
|
||||
[TT_WIN_UNF] = "Window Underflow",
|
||||
[TT_UNALIGNED] = "Unaligned Memory Access",
|
||||
[TT_FP_EXCP] = "FPU Exception",
|
||||
[TT_DFAULT] = "Data Access Fault",
|
||||
[TT_TOVF] = "Tag Overflow",
|
||||
[TT_EXTINT | 0x1] = "External Interrupt 1",
|
||||
[TT_EXTINT | 0x2] = "External Interrupt 2",
|
||||
[TT_EXTINT | 0x3] = "External Interrupt 3",
|
||||
[TT_EXTINT | 0x4] = "External Interrupt 4",
|
||||
[TT_EXTINT | 0x5] = "External Interrupt 5",
|
||||
[TT_EXTINT | 0x6] = "External Interrupt 6",
|
||||
[TT_EXTINT | 0x7] = "External Interrupt 7",
|
||||
[TT_EXTINT | 0x8] = "External Interrupt 8",
|
||||
[TT_EXTINT | 0x9] = "External Interrupt 9",
|
||||
[TT_EXTINT | 0xa] = "External Interrupt 10",
|
||||
[TT_EXTINT | 0xb] = "External Interrupt 11",
|
||||
[TT_EXTINT | 0xc] = "External Interrupt 12",
|
||||
[TT_EXTINT | 0xd] = "External Interrupt 13",
|
||||
[TT_EXTINT | 0xe] = "External Interrupt 14",
|
||||
[TT_EXTINT | 0xf] = "External Interrupt 15",
|
||||
[TT_TOVF] = "Tag Overflow",
|
||||
[TT_CODE_ACCESS] = "Instruction Access Error",
|
||||
[TT_DATA_ACCESS] = "Data Access Error",
|
||||
[TT_DIV_ZERO] = "Division By Zero",
|
||||
[TT_NCP_INSN] = "Coprocessor Disabled",
|
||||
};
|
||||
#endif
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_PCALL
|
||||
if (qemu_loglevel_mask(CPU_LOG_INT)) {
|
||||
static int count;
|
||||
const char *name;
|
||||
|
||||
if (intno < 0 || intno >= 0x100) {
|
||||
name = "Unknown";
|
||||
} else if (intno >= 0x80) {
|
||||
name = "Trap Instruction";
|
||||
} else {
|
||||
name = excp_names[intno];
|
||||
if (!name) {
|
||||
name = "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
qemu_log("%6d: %s (v=%02x)\n", count, name, intno);
|
||||
log_cpu_state(cs, 0);
|
||||
#if 0
|
||||
{
|
||||
int i;
|
||||
uint8_t *ptr;
|
||||
|
||||
qemu_log(" code=");
|
||||
ptr = (uint8_t *)env->pc;
|
||||
for (i = 0; i < 16; i++) {
|
||||
qemu_log(" %02x", ldub(ptr + i));
|
||||
}
|
||||
qemu_log("\n");
|
||||
}
|
||||
#endif
|
||||
count++;
|
||||
}
|
||||
#endif
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
if (env->psret == 0) {
|
||||
if (cs->exception_index == 0x80 &&
|
||||
env->def->features & CPU_FEATURE_TA0_SHUTDOWN) {
|
||||
qemu_system_shutdown_request();
|
||||
} else {
|
||||
cpu_abort(cs, "Trap 0x%02x while interrupts disabled, Error state",
|
||||
cs->exception_index);
|
||||
}
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
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;
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
/* IRQ acknowledgment */
|
||||
if ((intno & ~15) == TT_EXTINT && env->qemu_irq_ack != NULL) {
|
||||
env->qemu_irq_ack(env, env->irq_manager, intno);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
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;
|
||||
trace_int_helper_icache_freeze();
|
||||
}
|
||||
|
||||
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;
|
||||
trace_int_helper_dcache_freeze();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
#endif
|
205
target/sparc/int64_helper.c
Normal file
205
target/sparc/int64_helper.c
Normal file
|
@ -0,0 +1,205 @@
|
|||
/*
|
||||
* 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"
|
||||
#include "exec/log.h"
|
||||
#include "trace.h"
|
||||
|
||||
#define DEBUG_PCALL
|
||||
|
||||
#ifdef DEBUG_PCALL
|
||||
static const char * const excp_names[0x80] = {
|
||||
[TT_TFAULT] = "Instruction Access Fault",
|
||||
[TT_TMISS] = "Instruction Access MMU Miss",
|
||||
[TT_CODE_ACCESS] = "Instruction Access Error",
|
||||
[TT_ILL_INSN] = "Illegal Instruction",
|
||||
[TT_PRIV_INSN] = "Privileged Instruction",
|
||||
[TT_NFPU_INSN] = "FPU Disabled",
|
||||
[TT_FP_EXCP] = "FPU Exception",
|
||||
[TT_TOVF] = "Tag Overflow",
|
||||
[TT_CLRWIN] = "Clean Windows",
|
||||
[TT_DIV_ZERO] = "Division By Zero",
|
||||
[TT_DFAULT] = "Data Access Fault",
|
||||
[TT_DMISS] = "Data Access MMU Miss",
|
||||
[TT_DATA_ACCESS] = "Data Access Error",
|
||||
[TT_DPROT] = "Data Protection Error",
|
||||
[TT_UNALIGNED] = "Unaligned Memory Access",
|
||||
[TT_PRIV_ACT] = "Privileged Action",
|
||||
[TT_EXTINT | 0x1] = "External Interrupt 1",
|
||||
[TT_EXTINT | 0x2] = "External Interrupt 2",
|
||||
[TT_EXTINT | 0x3] = "External Interrupt 3",
|
||||
[TT_EXTINT | 0x4] = "External Interrupt 4",
|
||||
[TT_EXTINT | 0x5] = "External Interrupt 5",
|
||||
[TT_EXTINT | 0x6] = "External Interrupt 6",
|
||||
[TT_EXTINT | 0x7] = "External Interrupt 7",
|
||||
[TT_EXTINT | 0x8] = "External Interrupt 8",
|
||||
[TT_EXTINT | 0x9] = "External Interrupt 9",
|
||||
[TT_EXTINT | 0xa] = "External Interrupt 10",
|
||||
[TT_EXTINT | 0xb] = "External Interrupt 11",
|
||||
[TT_EXTINT | 0xc] = "External Interrupt 12",
|
||||
[TT_EXTINT | 0xd] = "External Interrupt 13",
|
||||
[TT_EXTINT | 0xe] = "External Interrupt 14",
|
||||
[TT_EXTINT | 0xf] = "External Interrupt 15",
|
||||
};
|
||||
#endif
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_PCALL
|
||||
if (qemu_loglevel_mask(CPU_LOG_INT)) {
|
||||
static int count;
|
||||
const char *name;
|
||||
|
||||
if (intno < 0 || intno >= 0x180) {
|
||||
name = "Unknown";
|
||||
} else if (intno >= 0x100) {
|
||||
name = "Trap Instruction";
|
||||
} else if (intno >= 0xc0) {
|
||||
name = "Window Fill";
|
||||
} else if (intno >= 0x80) {
|
||||
name = "Window Spill";
|
||||
} else {
|
||||
name = excp_names[intno];
|
||||
if (!name) {
|
||||
name = "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
qemu_log("%6d: %s (v=%04x)\n", count, name, intno);
|
||||
log_cpu_state(cs, 0);
|
||||
#if 0
|
||||
{
|
||||
int i;
|
||||
uint8_t *ptr;
|
||||
|
||||
qemu_log(" code=");
|
||||
ptr = (uint8_t *)env->pc;
|
||||
for (i = 0; i < 16; i++) {
|
||||
qemu_log(" %02x", ldub(ptr + i));
|
||||
}
|
||||
qemu_log("\n");
|
||||
}
|
||||
#endif
|
||||
count++;
|
||||
}
|
||||
#endif
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
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;
|
||||
}
|
||||
#endif
|
||||
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;
|
||||
|
||||
switch (intno) {
|
||||
case TT_IVEC:
|
||||
cpu_change_pstate(env, PS_PEF | PS_PRIV | PS_IG);
|
||||
break;
|
||||
case TT_TFAULT:
|
||||
case TT_DFAULT:
|
||||
case TT_TMISS ... TT_TMISS + 3:
|
||||
case TT_DMISS ... TT_DMISS + 3:
|
||||
case TT_DPROT ... TT_DPROT + 3:
|
||||
cpu_change_pstate(env, PS_PEF | PS_PRIV | PS_MG);
|
||||
break;
|
||||
default:
|
||||
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));
|
||||
}
|
||||
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 !defined(CONFIG_USER_ONLY)
|
||||
if (cpu_interrupts_enabled(env)) {
|
||||
cpu_check_irqs(env);
|
||||
}
|
||||
#endif
|
||||
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);
|
||||
}
|
||||
}
|
1709
target/sparc/ldst_helper.c
Normal file
1709
target/sparc/ldst_helper.c
Normal file
File diff suppressed because it is too large
Load diff
194
target/sparc/machine.c
Normal file
194
target/sparc/machine.c
Normal file
|
@ -0,0 +1,194 @@
|
|||
#include "qemu/osdep.h"
|
||||
#include "qemu-common.h"
|
||||
#include "cpu.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "hw/hw.h"
|
||||
#include "hw/boards.h"
|
||||
#include "qemu/timer.h"
|
||||
|
||||
#include "migration/cpu.h"
|
||||
|
||||
#ifdef TARGET_SPARC64
|
||||
static const VMStateDescription vmstate_cpu_timer = {
|
||||
.name = "cpu_timer",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32(frequency, CPUTimer),
|
||||
VMSTATE_UINT32(disabled, CPUTimer),
|
||||
VMSTATE_UINT64(disabled_mask, CPUTimer),
|
||||
VMSTATE_UINT32(npt, CPUTimer),
|
||||
VMSTATE_UINT64(npt_mask, CPUTimer),
|
||||
VMSTATE_INT64(clock_offset, CPUTimer),
|
||||
VMSTATE_TIMER_PTR(qtimer, CPUTimer),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
#define VMSTATE_CPU_TIMER(_f, _s) \
|
||||
VMSTATE_STRUCT_POINTER(_f, _s, vmstate_cpu_timer, CPUTimer)
|
||||
|
||||
static const VMStateDescription vmstate_trap_state = {
|
||||
.name = "trap_state",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT64(tpc, trap_state),
|
||||
VMSTATE_UINT64(tnpc, trap_state),
|
||||
VMSTATE_UINT64(tstate, trap_state),
|
||||
VMSTATE_UINT32(tt, trap_state),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static const VMStateDescription vmstate_tlb_entry = {
|
||||
.name = "tlb_entry",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT64(tag, SparcTLBEntry),
|
||||
VMSTATE_UINT64(tte, SparcTLBEntry),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
static int get_psr(QEMUFile *f, void *opaque, size_t size)
|
||||
{
|
||||
SPARCCPU *cpu = opaque;
|
||||
CPUSPARCState *env = &cpu->env;
|
||||
uint32_t val = qemu_get_be32(f);
|
||||
|
||||
/* needed to ensure that the wrapping registers are correctly updated */
|
||||
env->cwp = 0;
|
||||
cpu_put_psr_raw(env, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void put_psr(QEMUFile *f, void *opaque, size_t size)
|
||||
{
|
||||
SPARCCPU *cpu = opaque;
|
||||
CPUSPARCState *env = &cpu->env;
|
||||
uint32_t val;
|
||||
|
||||
val = cpu_get_psr(env);
|
||||
|
||||
qemu_put_be32(f, val);
|
||||
}
|
||||
|
||||
static const VMStateInfo vmstate_psr = {
|
||||
.name = "psr",
|
||||
.get = get_psr,
|
||||
.put = put_psr,
|
||||
};
|
||||
|
||||
static void cpu_pre_save(void *opaque)
|
||||
{
|
||||
SPARCCPU *cpu = opaque;
|
||||
CPUSPARCState *env = &cpu->env;
|
||||
|
||||
/* if env->cwp == env->nwindows - 1, this will set the ins of the last
|
||||
* window as the outs of the first window
|
||||
*/
|
||||
cpu_set_cwp(env, env->cwp);
|
||||
}
|
||||
|
||||
/* 32-bit SPARC retains migration compatibility with older versions
|
||||
* of QEMU; 64-bit SPARC has had a migration break since then, so the
|
||||
* versions are different.
|
||||
*/
|
||||
#ifndef TARGET_SPARC64
|
||||
#define SPARC_VMSTATE_VER 7
|
||||
#else
|
||||
#define SPARC_VMSTATE_VER 9
|
||||
#endif
|
||||
|
||||
const VMStateDescription vmstate_sparc_cpu = {
|
||||
.name = "cpu",
|
||||
.version_id = SPARC_VMSTATE_VER,
|
||||
.minimum_version_id = SPARC_VMSTATE_VER,
|
||||
.minimum_version_id_old = SPARC_VMSTATE_VER,
|
||||
.pre_save = cpu_pre_save,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINTTL_ARRAY(env.gregs, SPARCCPU, 8),
|
||||
VMSTATE_UINT32(env.nwindows, SPARCCPU),
|
||||
VMSTATE_VARRAY_MULTIPLY(env.regbase, SPARCCPU, env.nwindows, 16,
|
||||
vmstate_info_uinttl, target_ulong),
|
||||
VMSTATE_CPUDOUBLE_ARRAY(env.fpr, SPARCCPU, TARGET_DPREGS),
|
||||
VMSTATE_UINTTL(env.pc, SPARCCPU),
|
||||
VMSTATE_UINTTL(env.npc, SPARCCPU),
|
||||
VMSTATE_UINTTL(env.y, SPARCCPU),
|
||||
{
|
||||
|
||||
.name = "psr",
|
||||
.version_id = 0,
|
||||
.size = sizeof(uint32_t),
|
||||
.info = &vmstate_psr,
|
||||
.flags = VMS_SINGLE,
|
||||
.offset = 0,
|
||||
},
|
||||
VMSTATE_UINTTL(env.fsr, SPARCCPU),
|
||||
VMSTATE_UINTTL(env.tbr, SPARCCPU),
|
||||
VMSTATE_INT32(env.interrupt_index, SPARCCPU),
|
||||
VMSTATE_UINT32(env.pil_in, SPARCCPU),
|
||||
#ifndef TARGET_SPARC64
|
||||
/* MMU */
|
||||
VMSTATE_UINT32(env.wim, SPARCCPU),
|
||||
VMSTATE_UINT32_ARRAY(env.mmuregs, SPARCCPU, 32),
|
||||
VMSTATE_UINT64_ARRAY(env.mxccdata, SPARCCPU, 4),
|
||||
VMSTATE_UINT64_ARRAY(env.mxccregs, SPARCCPU, 8),
|
||||
VMSTATE_UINT32(env.mmubpctrv, SPARCCPU),
|
||||
VMSTATE_UINT32(env.mmubpctrc, SPARCCPU),
|
||||
VMSTATE_UINT32(env.mmubpctrs, SPARCCPU),
|
||||
VMSTATE_UINT64(env.mmubpaction, SPARCCPU),
|
||||
VMSTATE_UINT64_ARRAY(env.mmubpregs, SPARCCPU, 4),
|
||||
#else
|
||||
VMSTATE_UINT64(env.lsu, SPARCCPU),
|
||||
VMSTATE_UINT64_ARRAY(env.immuregs, SPARCCPU, 16),
|
||||
VMSTATE_UINT64_ARRAY(env.dmmuregs, SPARCCPU, 16),
|
||||
VMSTATE_STRUCT_ARRAY(env.itlb, SPARCCPU, 64, 0,
|
||||
vmstate_tlb_entry, SparcTLBEntry),
|
||||
VMSTATE_STRUCT_ARRAY(env.dtlb, SPARCCPU, 64, 0,
|
||||
vmstate_tlb_entry, SparcTLBEntry),
|
||||
VMSTATE_UINT32(env.mmu_version, SPARCCPU),
|
||||
VMSTATE_STRUCT_ARRAY(env.ts, SPARCCPU, MAXTL_MAX, 0,
|
||||
vmstate_trap_state, trap_state),
|
||||
VMSTATE_UINT32(env.xcc, SPARCCPU),
|
||||
VMSTATE_UINT32(env.asi, SPARCCPU),
|
||||
VMSTATE_UINT32(env.pstate, SPARCCPU),
|
||||
VMSTATE_UINT32(env.tl, SPARCCPU),
|
||||
VMSTATE_UINT32(env.cansave, SPARCCPU),
|
||||
VMSTATE_UINT32(env.canrestore, SPARCCPU),
|
||||
VMSTATE_UINT32(env.otherwin, SPARCCPU),
|
||||
VMSTATE_UINT32(env.wstate, SPARCCPU),
|
||||
VMSTATE_UINT32(env.cleanwin, SPARCCPU),
|
||||
VMSTATE_UINT64_ARRAY(env.agregs, SPARCCPU, 8),
|
||||
VMSTATE_UINT64_ARRAY(env.bgregs, SPARCCPU, 8),
|
||||
VMSTATE_UINT64_ARRAY(env.igregs, SPARCCPU, 8),
|
||||
VMSTATE_UINT64_ARRAY(env.mgregs, SPARCCPU, 8),
|
||||
VMSTATE_UINT64(env.fprs, SPARCCPU),
|
||||
VMSTATE_UINT64(env.tick_cmpr, SPARCCPU),
|
||||
VMSTATE_UINT64(env.stick_cmpr, SPARCCPU),
|
||||
VMSTATE_CPU_TIMER(env.tick, SPARCCPU),
|
||||
VMSTATE_CPU_TIMER(env.stick, SPARCCPU),
|
||||
VMSTATE_UINT64(env.gsr, SPARCCPU),
|
||||
VMSTATE_UINT32(env.gl, SPARCCPU),
|
||||
VMSTATE_UINT64(env.hpstate, SPARCCPU),
|
||||
VMSTATE_UINT64_ARRAY(env.htstate, SPARCCPU, MAXTL_MAX),
|
||||
VMSTATE_UINT64(env.hintp, SPARCCPU),
|
||||
VMSTATE_UINT64(env.htba, SPARCCPU),
|
||||
VMSTATE_UINT64(env.hver, SPARCCPU),
|
||||
VMSTATE_UINT64(env.hstick_cmpr, SPARCCPU),
|
||||
VMSTATE_UINT64(env.ssr, SPARCCPU),
|
||||
VMSTATE_CPU_TIMER(env.hstick, SPARCCPU),
|
||||
/* On SPARC32 env.psrpil and env.cwp are migrated as part of the PSR */
|
||||
VMSTATE_UINT32(env.psrpil, SPARCCPU),
|
||||
VMSTATE_UINT32(env.cwp, SPARCCPU),
|
||||
#endif
|
||||
VMSTATE_END_OF_LIST()
|
||||
},
|
||||
};
|
880
target/sparc/mmu_helper.c
Normal file
880
target/sparc/mmu_helper.c
Normal file
|
@ -0,0 +1,880 @@
|
|||
/*
|
||||
* 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"
|
||||
#include "trace.h"
|
||||
#include "exec/address-spaces.h"
|
||||
|
||||
/* Sparc MMU emulation */
|
||||
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
|
||||
int sparc_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int rw,
|
||||
int mmu_idx)
|
||||
{
|
||||
if (rw & 2) {
|
||||
cs->exception_index = TT_TFAULT;
|
||||
} else {
|
||||
cs->exception_index = TT_DFAULT;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#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,
|
||||
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 = CPU(sparc_env_get_cpu(env));
|
||||
|
||||
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 = ldl_phys(cs->as, pde_ptr);
|
||||
|
||||
/* 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 = ldl_phys(cs->as, pde_ptr);
|
||||
|
||||
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 = ldl_phys(cs->as, pde_ptr);
|
||||
|
||||
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 = ldl_phys(cs->as, pde_ptr);
|
||||
|
||||
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 */
|
||||
int sparc_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int rw,
|
||||
int mmu_idx)
|
||||
{
|
||||
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;
|
||||
|
||||
address &= TARGET_PAGE_MASK;
|
||||
error_code = get_physical_address(env, &paddr, &prot, &access_index,
|
||||
address, rw, mmu_idx, &page_size);
|
||||
vaddr = address;
|
||||
if (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 0;
|
||||
}
|
||||
|
||||
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 0;
|
||||
} else {
|
||||
if (rw & 2) {
|
||||
cs->exception_index = TT_TFAULT;
|
||||
} else {
|
||||
cs->exception_index = TT_DFAULT;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
target_ulong mmu_probe(CPUSPARCState *env, target_ulong address, int mmulev)
|
||||
{
|
||||
CPUState *cs = CPU(sparc_env_get_cpu(env));
|
||||
hwaddr pde_ptr;
|
||||
uint32_t pde;
|
||||
|
||||
/* Context base + context number */
|
||||
pde_ptr = (hwaddr)(env->mmuregs[1] << 4) +
|
||||
(env->mmuregs[2] << 2);
|
||||
pde = ldl_phys(cs->as, pde_ptr);
|
||||
|
||||
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 = ldl_phys(cs->as, pde_ptr);
|
||||
|
||||
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 = ldl_phys(cs->as, pde_ptr);
|
||||
|
||||
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 = ldl_phys(cs->as, pde_ptr);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUSPARCState *env)
|
||||
{
|
||||
CPUState *cs = CPU(sparc_env_get_cpu(env));
|
||||
target_ulong va, va1, va2;
|
||||
unsigned int n, m, o;
|
||||
hwaddr pde_ptr, pa;
|
||||
uint32_t pde;
|
||||
|
||||
pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2);
|
||||
pde = ldl_phys(cs->as, pde_ptr);
|
||||
(*cpu_fprintf)(f, "Root ptr: " TARGET_FMT_plx ", ctx: %d\n",
|
||||
(hwaddr)env->mmuregs[1] << 4, env->mmuregs[2]);
|
||||
for (n = 0, va = 0; n < 256; n++, va += 16 * 1024 * 1024) {
|
||||
pde = mmu_probe(env, va, 2);
|
||||
if (pde) {
|
||||
pa = cpu_get_phys_page_debug(cs, va);
|
||||
(*cpu_fprintf)(f, "VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_plx
|
||||
" PDE: " TARGET_FMT_lx "\n", va, pa, pde);
|
||||
for (m = 0, va1 = va; m < 64; m++, va1 += 256 * 1024) {
|
||||
pde = mmu_probe(env, va1, 1);
|
||||
if (pde) {
|
||||
pa = cpu_get_phys_page_debug(cs, va1);
|
||||
(*cpu_fprintf)(f, " VA: " TARGET_FMT_lx ", PA: "
|
||||
TARGET_FMT_plx " PDE: " TARGET_FMT_lx "\n",
|
||||
va1, pa, pde);
|
||||
for (o = 0, va2 = va1; o < 64; o++, va2 += 4 * 1024) {
|
||||
pde = mmu_probe(env, va2, 0);
|
||||
if (pde) {
|
||||
pa = cpu_get_phys_page_debug(cs, va2);
|
||||
(*cpu_fprintf)(f, " VA: " TARGET_FMT_lx ", PA: "
|
||||
TARGET_FMT_plx " PTE: "
|
||||
TARGET_FMT_lx "\n",
|
||||
va2, pa, pde);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
uint64_t mask;
|
||||
|
||||
switch (TTE_PGSIZE(tlb->tte)) {
|
||||
default:
|
||||
case 0x0: /* 8k */
|
||||
mask = 0xffffffffffffe000ULL;
|
||||
break;
|
||||
case 0x1: /* 64k */
|
||||
mask = 0xffffffffffff0000ULL;
|
||||
break;
|
||||
case 0x2: /* 512k */
|
||||
mask = 0xfffffffffff80000ULL;
|
||||
break;
|
||||
case 0x3: /* 4M */
|
||||
mask = 0xffffffffffc00000ULL;
|
||||
break;
|
||||
}
|
||||
|
||||
/* 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,
|
||||
target_ulong address, int rw, int mmu_idx)
|
||||
{
|
||||
CPUState *cs = CPU(sparc_env_get_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;
|
||||
|
||||
/* 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 */
|
||||
trace_mmu_helper_dfault(address, context, mmu_idx, env->tl);
|
||||
}
|
||||
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;
|
||||
|
||||
trace_mmu_helper_dprot(address, context, mmu_idx, env->tl);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
trace_mmu_helper_dmiss(address, context);
|
||||
|
||||
/*
|
||||
* On MMU misses:
|
||||
* - UltraSPARC IIi: SFSR and SFAR unmodified
|
||||
* - JPS1: SFAR updated and some fields of SFSR updated
|
||||
*/
|
||||
env->dmmu.tag_access = (address & ~0x1fffULL) | context;
|
||||
cs->exception_index = TT_DMISS;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int get_physical_address_code(CPUSPARCState *env,
|
||||
hwaddr *physical, int *prot,
|
||||
target_ulong address, int mmu_idx)
|
||||
{
|
||||
CPUState *cs = CPU(sparc_env_get_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;
|
||||
|
||||
trace_mmu_helper_tfault(address, context);
|
||||
|
||||
return 1;
|
||||
}
|
||||
*prot = PAGE_EXEC;
|
||||
TTE_SET_USED(env->itlb[i].tte);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
trace_mmu_helper_tmiss(address, context);
|
||||
|
||||
/* 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,
|
||||
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;
|
||||
|
||||
/* 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);
|
||||
}
|
||||
}
|
||||
|
||||
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, address,
|
||||
mmu_idx);
|
||||
} else {
|
||||
return get_physical_address_data(env, physical, prot, address, rw,
|
||||
mmu_idx);
|
||||
}
|
||||
}
|
||||
|
||||
/* Perform address translation */
|
||||
int sparc_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int rw,
|
||||
int mmu_idx)
|
||||
{
|
||||
SPARCCPU *cpu = SPARC_CPU(cs);
|
||||
CPUSPARCState *env = &cpu->env;
|
||||
target_ulong vaddr;
|
||||
hwaddr paddr;
|
||||
target_ulong page_size;
|
||||
int error_code = 0, prot, access_index;
|
||||
|
||||
address &= TARGET_PAGE_MASK;
|
||||
error_code = get_physical_address(env, &paddr, &prot, &access_index,
|
||||
address, rw, mmu_idx, &page_size);
|
||||
if (error_code == 0) {
|
||||
vaddr = address;
|
||||
|
||||
trace_mmu_helper_mmu_fault(address, paddr, mmu_idx, env->tl,
|
||||
env->dmmu.mmu_primary_context,
|
||||
env->dmmu.mmu_secondary_context);
|
||||
|
||||
tlb_set_page(cs, vaddr, paddr, prot, mmu_idx, page_size);
|
||||
return 0;
|
||||
}
|
||||
/* XXX */
|
||||
return 1;
|
||||
}
|
||||
|
||||
void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUSPARCState *env)
|
||||
{
|
||||
unsigned int i;
|
||||
const char *mask;
|
||||
|
||||
(*cpu_fprintf)(f, "MMU contexts: Primary: %" PRId64 ", Secondary: %"
|
||||
PRId64 "\n",
|
||||
env->dmmu.mmu_primary_context,
|
||||
env->dmmu.mmu_secondary_context);
|
||||
if ((env->lsu & DMMU_E) == 0) {
|
||||
(*cpu_fprintf)(f, "DMMU disabled\n");
|
||||
} else {
|
||||
(*cpu_fprintf)(f, "DMMU dump\n");
|
||||
for (i = 0; i < 64; i++) {
|
||||
switch (TTE_PGSIZE(env->dtlb[i].tte)) {
|
||||
default:
|
||||
case 0x0:
|
||||
mask = " 8k";
|
||||
break;
|
||||
case 0x1:
|
||||
mask = " 64k";
|
||||
break;
|
||||
case 0x2:
|
||||
mask = "512k";
|
||||
break;
|
||||
case 0x3:
|
||||
mask = " 4M";
|
||||
break;
|
||||
}
|
||||
if (TTE_IS_VALID(env->dtlb[i].tte)) {
|
||||
(*cpu_fprintf)(f, "[%02u] VA: %" PRIx64 ", PA: %llx"
|
||||
", %s, %s, %s, %s, ctx %" PRId64 " %s\n",
|
||||
i,
|
||||
env->dtlb[i].tag & (uint64_t)~0x1fffULL,
|
||||
TTE_PA(env->dtlb[i].tte),
|
||||
mask,
|
||||
TTE_IS_PRIV(env->dtlb[i].tte) ? "priv" : "user",
|
||||
TTE_IS_W_OK(env->dtlb[i].tte) ? "RW" : "RO",
|
||||
TTE_IS_LOCKED(env->dtlb[i].tte) ?
|
||||
"locked" : "unlocked",
|
||||
env->dtlb[i].tag & (uint64_t)0x1fffULL,
|
||||
TTE_IS_GLOBAL(env->dtlb[i].tte) ?
|
||||
"global" : "local");
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((env->lsu & IMMU_E) == 0) {
|
||||
(*cpu_fprintf)(f, "IMMU disabled\n");
|
||||
} else {
|
||||
(*cpu_fprintf)(f, "IMMU dump\n");
|
||||
for (i = 0; i < 64; i++) {
|
||||
switch (TTE_PGSIZE(env->itlb[i].tte)) {
|
||||
default:
|
||||
case 0x0:
|
||||
mask = " 8k";
|
||||
break;
|
||||
case 0x1:
|
||||
mask = " 64k";
|
||||
break;
|
||||
case 0x2:
|
||||
mask = "512k";
|
||||
break;
|
||||
case 0x3:
|
||||
mask = " 4M";
|
||||
break;
|
||||
}
|
||||
if (TTE_IS_VALID(env->itlb[i].tte)) {
|
||||
(*cpu_fprintf)(f, "[%02u] VA: %" PRIx64 ", PA: %llx"
|
||||
", %s, %s, %s, ctx %" PRId64 " %s\n",
|
||||
i,
|
||||
env->itlb[i].tag & (uint64_t)~0x1fffULL,
|
||||
TTE_PA(env->itlb[i].tte),
|
||||
mask,
|
||||
TTE_IS_PRIV(env->itlb[i].tte) ? "priv" : "user",
|
||||
TTE_IS_LOCKED(env->itlb[i].tte) ?
|
||||
"locked" : "unlocked",
|
||||
env->itlb[i].tag & (uint64_t)0x1fffULL,
|
||||
TTE_IS_GLOBAL(env->itlb[i].tte) ?
|
||||
"global" : "local");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#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;
|
||||
|
||||
return get_physical_address(env, phys, &prot, &access_index, 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);
|
||||
MemoryRegionSection section;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
section = memory_region_find(get_system_memory(), phys_addr, 1);
|
||||
memory_region_unref(section.mr);
|
||||
if (!int128_nz(section.size)) {
|
||||
return -1;
|
||||
}
|
||||
return phys_addr;
|
||||
}
|
||||
#endif
|
159
target/sparc/monitor.c
Normal file
159
target/sparc/monitor.c
Normal file
|
@ -0,0 +1,159 @@
|
|||
/*
|
||||
* QEMU monitor
|
||||
*
|
||||
* Copyright (c) 2003-2004 Fabrice Bellard
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#include "qemu/osdep.h"
|
||||
#include "cpu.h"
|
||||
#include "monitor/monitor.h"
|
||||
#include "monitor/hmp-target.h"
|
||||
#include "hmp.h"
|
||||
|
||||
|
||||
void hmp_info_tlb(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
CPUArchState *env1 = mon_get_cpu_env();
|
||||
|
||||
dump_mmu((FILE*)mon, (fprintf_function)monitor_printf, env1);
|
||||
}
|
||||
|
||||
#ifndef TARGET_SPARC64
|
||||
static target_long monitor_get_psr (const struct MonitorDef *md, int val)
|
||||
{
|
||||
CPUArchState *env = mon_get_cpu_env();
|
||||
|
||||
return cpu_get_psr(env);
|
||||
}
|
||||
#endif
|
||||
|
||||
static target_long monitor_get_reg(const struct MonitorDef *md, int val)
|
||||
{
|
||||
CPUArchState *env = mon_get_cpu_env();
|
||||
return env->regwptr[val];
|
||||
}
|
||||
|
||||
const MonitorDef monitor_defs[] = {
|
||||
{ "g0", offsetof(CPUSPARCState, gregs[0]) },
|
||||
{ "g1", offsetof(CPUSPARCState, gregs[1]) },
|
||||
{ "g2", offsetof(CPUSPARCState, gregs[2]) },
|
||||
{ "g3", offsetof(CPUSPARCState, gregs[3]) },
|
||||
{ "g4", offsetof(CPUSPARCState, gregs[4]) },
|
||||
{ "g5", offsetof(CPUSPARCState, gregs[5]) },
|
||||
{ "g6", offsetof(CPUSPARCState, gregs[6]) },
|
||||
{ "g7", offsetof(CPUSPARCState, gregs[7]) },
|
||||
{ "o0", 0, monitor_get_reg },
|
||||
{ "o1", 1, monitor_get_reg },
|
||||
{ "o2", 2, monitor_get_reg },
|
||||
{ "o3", 3, monitor_get_reg },
|
||||
{ "o4", 4, monitor_get_reg },
|
||||
{ "o5", 5, monitor_get_reg },
|
||||
{ "o6", 6, monitor_get_reg },
|
||||
{ "o7", 7, monitor_get_reg },
|
||||
{ "l0", 8, monitor_get_reg },
|
||||
{ "l1", 9, monitor_get_reg },
|
||||
{ "l2", 10, monitor_get_reg },
|
||||
{ "l3", 11, monitor_get_reg },
|
||||
{ "l4", 12, monitor_get_reg },
|
||||
{ "l5", 13, monitor_get_reg },
|
||||
{ "l6", 14, monitor_get_reg },
|
||||
{ "l7", 15, monitor_get_reg },
|
||||
{ "i0", 16, monitor_get_reg },
|
||||
{ "i1", 17, monitor_get_reg },
|
||||
{ "i2", 18, monitor_get_reg },
|
||||
{ "i3", 19, monitor_get_reg },
|
||||
{ "i4", 20, monitor_get_reg },
|
||||
{ "i5", 21, monitor_get_reg },
|
||||
{ "i6", 22, monitor_get_reg },
|
||||
{ "i7", 23, monitor_get_reg },
|
||||
{ "pc", offsetof(CPUSPARCState, pc) },
|
||||
{ "npc", offsetof(CPUSPARCState, npc) },
|
||||
{ "y", offsetof(CPUSPARCState, y) },
|
||||
#ifndef TARGET_SPARC64
|
||||
{ "psr", 0, &monitor_get_psr, },
|
||||
{ "wim", offsetof(CPUSPARCState, wim) },
|
||||
#endif
|
||||
{ "tbr", offsetof(CPUSPARCState, tbr) },
|
||||
{ "fsr", offsetof(CPUSPARCState, fsr) },
|
||||
{ "f0", offsetof(CPUSPARCState, fpr[0].l.upper) },
|
||||
{ "f1", offsetof(CPUSPARCState, fpr[0].l.lower) },
|
||||
{ "f2", offsetof(CPUSPARCState, fpr[1].l.upper) },
|
||||
{ "f3", offsetof(CPUSPARCState, fpr[1].l.lower) },
|
||||
{ "f4", offsetof(CPUSPARCState, fpr[2].l.upper) },
|
||||
{ "f5", offsetof(CPUSPARCState, fpr[2].l.lower) },
|
||||
{ "f6", offsetof(CPUSPARCState, fpr[3].l.upper) },
|
||||
{ "f7", offsetof(CPUSPARCState, fpr[3].l.lower) },
|
||||
{ "f8", offsetof(CPUSPARCState, fpr[4].l.upper) },
|
||||
{ "f9", offsetof(CPUSPARCState, fpr[4].l.lower) },
|
||||
{ "f10", offsetof(CPUSPARCState, fpr[5].l.upper) },
|
||||
{ "f11", offsetof(CPUSPARCState, fpr[5].l.lower) },
|
||||
{ "f12", offsetof(CPUSPARCState, fpr[6].l.upper) },
|
||||
{ "f13", offsetof(CPUSPARCState, fpr[6].l.lower) },
|
||||
{ "f14", offsetof(CPUSPARCState, fpr[7].l.upper) },
|
||||
{ "f15", offsetof(CPUSPARCState, fpr[7].l.lower) },
|
||||
{ "f16", offsetof(CPUSPARCState, fpr[8].l.upper) },
|
||||
{ "f17", offsetof(CPUSPARCState, fpr[8].l.lower) },
|
||||
{ "f18", offsetof(CPUSPARCState, fpr[9].l.upper) },
|
||||
{ "f19", offsetof(CPUSPARCState, fpr[9].l.lower) },
|
||||
{ "f20", offsetof(CPUSPARCState, fpr[10].l.upper) },
|
||||
{ "f21", offsetof(CPUSPARCState, fpr[10].l.lower) },
|
||||
{ "f22", offsetof(CPUSPARCState, fpr[11].l.upper) },
|
||||
{ "f23", offsetof(CPUSPARCState, fpr[11].l.lower) },
|
||||
{ "f24", offsetof(CPUSPARCState, fpr[12].l.upper) },
|
||||
{ "f25", offsetof(CPUSPARCState, fpr[12].l.lower) },
|
||||
{ "f26", offsetof(CPUSPARCState, fpr[13].l.upper) },
|
||||
{ "f27", offsetof(CPUSPARCState, fpr[13].l.lower) },
|
||||
{ "f28", offsetof(CPUSPARCState, fpr[14].l.upper) },
|
||||
{ "f29", offsetof(CPUSPARCState, fpr[14].l.lower) },
|
||||
{ "f30", offsetof(CPUSPARCState, fpr[15].l.upper) },
|
||||
{ "f31", offsetof(CPUSPARCState, fpr[15].l.lower) },
|
||||
#ifdef TARGET_SPARC64
|
||||
{ "f32", offsetof(CPUSPARCState, fpr[16]) },
|
||||
{ "f34", offsetof(CPUSPARCState, fpr[17]) },
|
||||
{ "f36", offsetof(CPUSPARCState, fpr[18]) },
|
||||
{ "f38", offsetof(CPUSPARCState, fpr[19]) },
|
||||
{ "f40", offsetof(CPUSPARCState, fpr[20]) },
|
||||
{ "f42", offsetof(CPUSPARCState, fpr[21]) },
|
||||
{ "f44", offsetof(CPUSPARCState, fpr[22]) },
|
||||
{ "f46", offsetof(CPUSPARCState, fpr[23]) },
|
||||
{ "f48", offsetof(CPUSPARCState, fpr[24]) },
|
||||
{ "f50", offsetof(CPUSPARCState, fpr[25]) },
|
||||
{ "f52", offsetof(CPUSPARCState, fpr[26]) },
|
||||
{ "f54", offsetof(CPUSPARCState, fpr[27]) },
|
||||
{ "f56", offsetof(CPUSPARCState, fpr[28]) },
|
||||
{ "f58", offsetof(CPUSPARCState, fpr[29]) },
|
||||
{ "f60", offsetof(CPUSPARCState, fpr[30]) },
|
||||
{ "f62", offsetof(CPUSPARCState, fpr[31]) },
|
||||
{ "asi", offsetof(CPUSPARCState, asi) },
|
||||
{ "pstate", offsetof(CPUSPARCState, pstate) },
|
||||
{ "cansave", offsetof(CPUSPARCState, cansave) },
|
||||
{ "canrestore", offsetof(CPUSPARCState, canrestore) },
|
||||
{ "otherwin", offsetof(CPUSPARCState, otherwin) },
|
||||
{ "wstate", offsetof(CPUSPARCState, wstate) },
|
||||
{ "cleanwin", offsetof(CPUSPARCState, cleanwin) },
|
||||
{ "fprs", offsetof(CPUSPARCState, fprs) },
|
||||
#endif
|
||||
{ NULL },
|
||||
};
|
||||
|
||||
const MonitorDef *target_monitor_defs(void)
|
||||
{
|
||||
return monitor_defs;
|
||||
}
|
28
target/sparc/trace-events
Normal file
28
target/sparc/trace-events
Normal file
|
@ -0,0 +1,28 @@
|
|||
# See docs/tracing.txt for syntax documentation.
|
||||
|
||||
# target/sparc/mmu_helper.c
|
||||
mmu_helper_dfault(uint64_t address, uint64_t context, int mmu_idx, uint32_t tl) "DFAULT at %"PRIx64" context %"PRIx64" mmu_idx=%d tl=%d"
|
||||
mmu_helper_dprot(uint64_t address, uint64_t context, int mmu_idx, uint32_t tl) "DPROT at %"PRIx64" context %"PRIx64" mmu_idx=%d tl=%d"
|
||||
mmu_helper_dmiss(uint64_t address, uint64_t context) "DMISS at %"PRIx64" context %"PRIx64
|
||||
mmu_helper_tfault(uint64_t address, uint64_t context) "TFAULT at %"PRIx64" context %"PRIx64
|
||||
mmu_helper_tmiss(uint64_t address, uint64_t context) "TMISS at %"PRIx64" context %"PRIx64
|
||||
mmu_helper_get_phys_addr_code(uint32_t tl, int mmu_idx, uint64_t prim_context, uint64_t sec_context, uint64_t address) "tl=%d mmu_idx=%d primary context=%"PRIx64" secondary context=%"PRIx64" address=%"PRIx64
|
||||
mmu_helper_get_phys_addr_data(uint32_t tl, int mmu_idx, uint64_t prim_context, uint64_t sec_context, uint64_t address) "tl=%d mmu_idx=%d primary context=%"PRIx64" secondary context=%"PRIx64" address=%"PRIx64
|
||||
mmu_helper_mmu_fault(uint64_t address, uint64_t paddr, int mmu_idx, uint32_t tl, uint64_t prim_context, uint64_t sec_context) "Translate at %"PRIx64" -> %"PRIx64", mmu_idx=%d tl=%d primary context=%"PRIx64" secondary context=%"PRIx64
|
||||
|
||||
# target/sparc/int64_helper.c
|
||||
int_helper_set_softint(uint32_t softint) "new %08x"
|
||||
int_helper_clear_softint(uint32_t softint) "new %08x"
|
||||
int_helper_write_softint(uint32_t softint) "new %08x"
|
||||
|
||||
# target/sparc/int32_helper.c
|
||||
int_helper_icache_freeze(void) "Instruction cache: freeze"
|
||||
int_helper_dcache_freeze(void) "Data cache: freeze"
|
||||
|
||||
# target/sparc/win_helper.c
|
||||
win_helper_gregset_error(uint32_t pstate) "ERROR in get_gregset: active pstate bits=%x"
|
||||
win_helper_switch_pstate(uint32_t pstate_regs, uint32_t new_pstate_regs) "change_pstate: switching regs old=%x new=%x"
|
||||
win_helper_no_switch_pstate(uint32_t new_pstate_regs) "change_pstate: regs new=%x (unchanged)"
|
||||
win_helper_wrpil(uint32_t psrpil, uint32_t new_pil) "old=%x new=%x"
|
||||
win_helper_done(uint32_t tl) "tl=%d"
|
||||
win_helper_retry(uint32_t tl) "tl=%d"
|
5924
target/sparc/translate.c
Normal file
5924
target/sparc/translate.c
Normal file
File diff suppressed because it is too large
Load diff
490
target/sparc/vis_helper.c
Normal file
490
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;
|
||||
}
|
400
target/sparc/win_helper.c
Normal file
400
target/sparc/win_helper.c
Normal file
|
@ -0,0 +1,400 @@
|
|||
/*
|
||||
* 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"
|
||||
#include "trace.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
|
||||
}
|
||||
|
||||
void cpu_put_psr(CPUSPARCState *env, target_ulong val)
|
||||
{
|
||||
cpu_put_psr_raw(env, val);
|
||||
#if ((!defined(TARGET_SPARC64)) && !defined(CONFIG_USER_ONLY))
|
||||
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(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)
|
||||
{
|
||||
switch (pstate) {
|
||||
default:
|
||||
trace_win_helper_gregset_error(pstate);
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
|
||||
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 is not implemented in this case */
|
||||
new_pstate &= ~PS_AG;
|
||||
}
|
||||
|
||||
pstate_regs = env->pstate & 0xc01;
|
||||
new_pstate_regs = new_pstate & 0xc01;
|
||||
|
||||
if (new_pstate_regs != pstate_regs) {
|
||||
trace_win_helper_switch_pstate(pstate_regs, new_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);
|
||||
} else {
|
||||
trace_win_helper_no_switch_pstate(new_pstate_regs);
|
||||
}
|
||||
env->pstate = new_pstate;
|
||||
}
|
||||
|
||||
void helper_wrpstate(CPUSPARCState *env, target_ulong new_state)
|
||||
{
|
||||
cpu_change_pstate(env, new_state & 0xf3f);
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
if (cpu_interrupts_enabled(env)) {
|
||||
cpu_check_irqs(env);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void helper_wrpil(CPUSPARCState *env, target_ulong new_pil)
|
||||
{
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
trace_win_helper_wrpil(env->psrpil, (uint32_t)new_pil);
|
||||
|
||||
env->psrpil = new_pil;
|
||||
|
||||
if (cpu_interrupts_enabled(env)) {
|
||||
cpu_check_irqs(env);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
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);
|
||||
env->tl--;
|
||||
|
||||
trace_win_helper_done(env->tl);
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
if (cpu_interrupts_enabled(env)) {
|
||||
cpu_check_irqs(env);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
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);
|
||||
env->tl--;
|
||||
|
||||
trace_win_helper_retry(env->tl);
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
if (cpu_interrupts_enabled(env)) {
|
||||
cpu_check_irqs(env);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
Loading…
Add table
Add a link
Reference in a new issue