diff options
Diffstat (limited to 'qemu/target-sparc')
-rw-r--r-- | qemu/target-sparc/Makefile.objs | 7 | ||||
-rw-r--r-- | qemu/target-sparc/TODO | 88 | ||||
-rw-r--r-- | qemu/target-sparc/cc_helper.c | 486 | ||||
-rw-r--r-- | qemu/target-sparc/cpu-qom.h | 92 | ||||
-rw-r--r-- | qemu/target-sparc/cpu.c | 894 | ||||
-rw-r--r-- | qemu/target-sparc/cpu.h | 737 | ||||
-rw-r--r-- | qemu/target-sparc/fop_helper.c | 468 | ||||
-rw-r--r-- | qemu/target-sparc/gdbstub.c | 208 | ||||
-rw-r--r-- | qemu/target-sparc/helper.c | 262 | ||||
-rw-r--r-- | qemu/target-sparc/helper.h | 175 | ||||
-rw-r--r-- | qemu/target-sparc/int32_helper.c | 175 | ||||
-rw-r--r-- | qemu/target-sparc/int64_helper.c | 205 | ||||
-rw-r--r-- | qemu/target-sparc/ldst_helper.c | 2456 | ||||
-rw-r--r-- | qemu/target-sparc/machine.c | 191 | ||||
-rw-r--r-- | qemu/target-sparc/mmu_helper.c | 868 | ||||
-rw-r--r-- | qemu/target-sparc/monitor.c | 159 | ||||
-rw-r--r-- | qemu/target-sparc/translate.c | 5447 | ||||
-rw-r--r-- | qemu/target-sparc/vis_helper.c | 490 | ||||
-rw-r--r-- | qemu/target-sparc/win_helper.c | 399 |
19 files changed, 0 insertions, 13807 deletions
diff --git a/qemu/target-sparc/Makefile.objs b/qemu/target-sparc/Makefile.objs deleted file mode 100644 index ec905698c..000000000 --- a/qemu/target-sparc/Makefile.objs +++ /dev/null @@ -1,7 +0,0 @@ -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 diff --git a/qemu/target-sparc/TODO b/qemu/target-sparc/TODO deleted file mode 100644 index b8c727e85..000000000 --- a/qemu/target-sparc/TODO +++ /dev/null @@ -1,88 +0,0 @@ -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 diff --git a/qemu/target-sparc/cc_helper.c b/qemu/target-sparc/cc_helper.c deleted file mode 100644 index 44c440934..000000000 --- a/qemu/target-sparc/cc_helper.c +++ /dev/null @@ -1,486 +0,0 @@ -/* - * 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) -{ - uint32_t ret; - - ret = get_C_addx_xcc(CC_DST, CC_SRC, CC_SRC2); - return ret; -} -#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) -{ - uint32_t ret; - - ret = get_C_addx_icc(CC_DST, CC_SRC, CC_SRC2); - return ret; -} - -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) -{ - uint32_t ret; - - ret = get_C_subx_xcc(CC_DST, CC_SRC, CC_SRC2); - return ret; -} -#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) -{ - uint32_t ret; - - ret = get_C_subx_icc(CC_DST, CC_SRC, CC_SRC2); - return ret; -} - -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) -{ - uint32_t ret; - - ret = icc_table[CC_OP].compute_c(env) >> PSR_CARRY_SHIFT; - return ret; -} diff --git a/qemu/target-sparc/cpu-qom.h b/qemu/target-sparc/cpu-qom.h deleted file mode 100644 index 5096b1047..000000000 --- a/qemu/target-sparc/cpu-qom.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * 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" -#include "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; - -/** - * SPARCCPU: - * @env: #CPUSPARCState - * - * A SPARC CPU. - */ -typedef struct SPARCCPU { - /*< private >*/ - CPUState parent_obj; - /*< public >*/ - - CPUSPARCState env; -} SPARCCPU; - -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, int is_write, - int is_user, uintptr_t retaddr); - -#endif diff --git a/qemu/target-sparc/cpu.c b/qemu/target-sparc/cpu.c deleted file mode 100644 index fe4119e2b..000000000 --- a/qemu/target-sparc/cpu.c +++ /dev/null @@ -1,894 +0,0 @@ -/* - * 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" - -//#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 int cpu_sparc_register(SPARCCPU *cpu, const char *cpu_model) -{ - CPUClass *cc = CPU_GET_CLASS(cpu); - 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_new0(sparc_def_t, 1); - memcpy(env->def, def, sizeof(*def)); - - featurestr = strtok(NULL, ","); - cc->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) -{ - SPARCCPUClass *scc = SPARC_CPU_GET_CLASS(dev); -#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 - - qemu_init_vcpu(CPU(dev)); - - 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; - cpu_exec_init(cs, &error_abort); - - 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->parse_features = sparc_cpu_parse_features; - 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 - - /* - * Reason: sparc_cpu_initfn() calls cpu_exec_init(), which saves - * the object in cpus -> dangling pointer after final - * object_unref(). - */ - dc->cannot_destroy_with_object_finalize_yet = true; -} - -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) diff --git a/qemu/target-sparc/cpu.h b/qemu/target-sparc/cpu.h deleted file mode 100644 index dc4612275..000000000 --- a/qemu/target-sparc/cpu.h +++ /dev/null @@ -1,737 +0,0 @@ -#ifndef CPU_SPARC_H -#define CPU_SPARC_H - -#include "qemu-common.h" -#include "qemu/bswap.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) - -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 2 -#else -#define NB_MMU_MODES 6 -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; -}; - -#include "cpu-qom.h" - -#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 */ -int cpu_sparc_exec(CPUState *cpu); - -/* 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_exec cpu_sparc_exec -#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_MODE0_SUFFIX _user -#define MMU_USER_SECONDARY_IDX 1 -#define MMU_MODE1_SUFFIX _user_secondary -#define MMU_KERNEL_IDX 2 -#define MMU_MODE2_SUFFIX _kernel -#define MMU_KERNEL_SECONDARY_IDX 3 -#define MMU_MODE3_SUFFIX _kernel_secondary -#define MMU_NUCLEUS_IDX 4 -#define MMU_MODE4_SUFFIX _nucleus -#define MMU_HYPV_IDX 5 -#define MMU_MODE5_SUFFIX _hypv -#else -#define MMU_USER_IDX 0 -#define MMU_MODE0_SUFFIX _user -#define MMU_KERNEL_IDX 1 -#define MMU_MODE1_SUFFIX _kernel -#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 *env1, bool ifetch) -{ -#if defined(CONFIG_USER_ONLY) - return MMU_USER_IDX; -#elif !defined(TARGET_SPARC64) - return env1->psrs; -#else - if (env1->tl > 0) { - return MMU_NUCLEUS_IDX; - } else if (cpu_hypervisor_mode(env1)) { - return MMU_HYPV_IDX; - } else if (cpu_supervisor_mode(env1)) { - 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_FPU_ENABLED (1 << 4) -#define TB_FLAG_AM_ENABLED (1 << 5) - -static inline void cpu_get_tb_cpu_state(CPUSPARCState *env, target_ulong *pc, - target_ulong *cs_base, int *flags) -{ - *pc = env->pc; - *cs_base = env->npc; -#ifdef TARGET_SPARC64 - // AM . Combined FPU enable bits . PRIV . DMMU enabled . IMMU enabled - *flags = (env->pstate & PS_PRIV) /* 2 */ - | ((env->lsu & (DMMU_E | IMMU_E)) >> 2) /* 1, 0 */ - | ((env->tl & 0xff) << 8) - | (env->dmmu.mmu_primary_context << 16); /* 16... */ - if (env->pstate & PS_AM) { - *flags |= TB_FLAG_AM_ENABLED; - } - if ((env->def->features & CPU_FEATURE_FLOAT) && (env->pstate & PS_PEF) - && (env->fprs & FPRS_FEF)) { - *flags |= TB_FLAG_FPU_ENABLED; - } -#else - // FPU enable . Supervisor - *flags = env->psrs; - if ((env->def->features & CPU_FEATURE_FLOAT) && env->psref) { - *flags |= TB_FLAG_FPU_ENABLED; - } -#endif -} - -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 -} - -#include "exec/exec-all.h" - -#endif diff --git a/qemu/target-sparc/fop_helper.c b/qemu/target-sparc/fop_helper.c deleted file mode 100644 index 08306436a..000000000 --- a/qemu/target-sparc/fop_helper.c +++ /dev/null @@ -1,468 +0,0 @@ -/* - * 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/helper-proto.h" - -#define QT0 (env->qt0) -#define QT1 (env->qt1) - -static void check_ieee_exceptions(CPUSPARCState *env) -{ - target_ulong status; - - status = get_float_exception_flags(&env->fp_status); - if (status) { - /* Copy IEEE 754 flags into FSR */ - if (status & float_flag_invalid) { - env->fsr |= FSR_NVC; - } - if (status & float_flag_overflow) { - env->fsr |= FSR_OFC; - } - if (status & float_flag_underflow) { - env->fsr |= FSR_UFC; - } - if (status & float_flag_divbyzero) { - env->fsr |= FSR_DZC; - } - if (status & float_flag_inexact) { - env->fsr |= FSR_NXC; - } - - if ((env->fsr & FSR_CEXC_MASK) & ((env->fsr & FSR_TEM_MASK) >> 23)) { - /* Unmasked exception, generate a trap */ - env->fsr |= FSR_FTT_IEEE_EXCP; - helper_raise_exception(env, TT_FP_EXCP); - } else { - /* Accumulate exceptions */ - env->fsr |= (env->fsr & FSR_CEXC_MASK) << 5; - } - } -} - -static inline void clear_float_exceptions(CPUSPARCState *env) -{ - set_float_exception_flags(0, &env->fp_status); -} - -#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) \ - { \ - float32 ret; \ - clear_float_exceptions(env); \ - ret = float32_ ## name (src1, src2, &env->fp_status); \ - check_ieee_exceptions(env); \ - return ret; \ - } \ - float64 helper_f ## name ## d (CPUSPARCState * env, float64 src1,\ - float64 src2) \ - { \ - float64 ret; \ - clear_float_exceptions(env); \ - ret = float64_ ## name (src1, src2, &env->fp_status); \ - check_ieee_exceptions(env); \ - return ret; \ - } \ - F_HELPER(name, q) \ - { \ - clear_float_exceptions(env); \ - QT0 = float128_ ## name (QT0, QT1, &env->fp_status); \ - check_ieee_exceptions(env); \ - } - -F_BINOP(add); -F_BINOP(sub); -F_BINOP(mul); -F_BINOP(div); -#undef F_BINOP - -float64 helper_fsmuld(CPUSPARCState *env, float32 src1, float32 src2) -{ - float64 ret; - clear_float_exceptions(env); - ret = float64_mul(float32_to_float64(src1, &env->fp_status), - float32_to_float64(src2, &env->fp_status), - &env->fp_status); - check_ieee_exceptions(env); - return ret; -} - -void helper_fdmulq(CPUSPARCState *env, float64 src1, float64 src2) -{ - clear_float_exceptions(env); - QT0 = float128_mul(float64_to_float128(src1, &env->fp_status), - float64_to_float128(src2, &env->fp_status), - &env->fp_status); - check_ieee_exceptions(env); -} - -float32 helper_fnegs(float32 src) -{ - 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) -{ - /* Inexact error possible converting int to float. */ - float32 ret; - clear_float_exceptions(env); - ret = int32_to_float32(src, &env->fp_status); - check_ieee_exceptions(env); - return ret; -} - -float64 helper_fitod(CPUSPARCState *env, int32_t src) -{ - /* No possible exceptions converting int to double. */ - return int32_to_float64(src, &env->fp_status); -} - -void helper_fitoq(CPUSPARCState *env, int32_t src) -{ - /* No possible exceptions converting int to long double. */ - QT0 = int32_to_float128(src, &env->fp_status); -} - -#ifdef TARGET_SPARC64 -float32 helper_fxtos(CPUSPARCState *env, int64_t src) -{ - float32 ret; - clear_float_exceptions(env); - ret = int64_to_float32(src, &env->fp_status); - check_ieee_exceptions(env); - return ret; -} - -float64 helper_fxtod(CPUSPARCState *env, int64_t src) -{ - float64 ret; - clear_float_exceptions(env); - ret = int64_to_float64(src, &env->fp_status); - check_ieee_exceptions(env); - return ret; -} - -void helper_fxtoq(CPUSPARCState *env, int64_t src) -{ - /* No possible exceptions converting long long to long double. */ - QT0 = int64_to_float128(src, &env->fp_status); -} -#endif -#undef F_HELPER - -/* floating point conversion */ -float32 helper_fdtos(CPUSPARCState *env, float64 src) -{ - float32 ret; - clear_float_exceptions(env); - ret = float64_to_float32(src, &env->fp_status); - check_ieee_exceptions(env); - return ret; -} - -float64 helper_fstod(CPUSPARCState *env, float32 src) -{ - float64 ret; - clear_float_exceptions(env); - ret = float32_to_float64(src, &env->fp_status); - check_ieee_exceptions(env); - return ret; -} - -float32 helper_fqtos(CPUSPARCState *env) -{ - float32 ret; - clear_float_exceptions(env); - ret = float128_to_float32(QT1, &env->fp_status); - check_ieee_exceptions(env); - return ret; -} - -void helper_fstoq(CPUSPARCState *env, float32 src) -{ - clear_float_exceptions(env); - QT0 = float32_to_float128(src, &env->fp_status); - check_ieee_exceptions(env); -} - -float64 helper_fqtod(CPUSPARCState *env) -{ - float64 ret; - clear_float_exceptions(env); - ret = float128_to_float64(QT1, &env->fp_status); - check_ieee_exceptions(env); - return ret; -} - -void helper_fdtoq(CPUSPARCState *env, float64 src) -{ - clear_float_exceptions(env); - QT0 = float64_to_float128(src, &env->fp_status); - check_ieee_exceptions(env); -} - -/* Float to integer conversion. */ -int32_t helper_fstoi(CPUSPARCState *env, float32 src) -{ - int32_t ret; - clear_float_exceptions(env); - ret = float32_to_int32_round_to_zero(src, &env->fp_status); - check_ieee_exceptions(env); - return ret; -} - -int32_t helper_fdtoi(CPUSPARCState *env, float64 src) -{ - int32_t ret; - clear_float_exceptions(env); - ret = float64_to_int32_round_to_zero(src, &env->fp_status); - check_ieee_exceptions(env); - return ret; -} - -int32_t helper_fqtoi(CPUSPARCState *env) -{ - int32_t ret; - clear_float_exceptions(env); - ret = float128_to_int32_round_to_zero(QT1, &env->fp_status); - check_ieee_exceptions(env); - return ret; -} - -#ifdef TARGET_SPARC64 -int64_t helper_fstox(CPUSPARCState *env, float32 src) -{ - int64_t ret; - clear_float_exceptions(env); - ret = float32_to_int64_round_to_zero(src, &env->fp_status); - check_ieee_exceptions(env); - return ret; -} - -int64_t helper_fdtox(CPUSPARCState *env, float64 src) -{ - int64_t ret; - clear_float_exceptions(env); - ret = float64_to_int64_round_to_zero(src, &env->fp_status); - check_ieee_exceptions(env); - return ret; -} - -int64_t helper_fqtox(CPUSPARCState *env) -{ - int64_t ret; - clear_float_exceptions(env); - ret = float128_to_int64_round_to_zero(QT1, &env->fp_status); - check_ieee_exceptions(env); - return ret; -} -#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) -{ - float32 ret; - clear_float_exceptions(env); - ret = float32_sqrt(src, &env->fp_status); - check_ieee_exceptions(env); - return ret; -} - -float64 helper_fsqrtd(CPUSPARCState *env, float64 src) -{ - float64 ret; - clear_float_exceptions(env); - ret = float64_sqrt(src, &env->fp_status); - check_ieee_exceptions(env); - return ret; -} - -void helper_fsqrtq(CPUSPARCState *env) -{ - clear_float_exceptions(env); - QT0 = float128_sqrt(QT1, &env->fp_status); - check_ieee_exceptions(env); -} - -#define GEN_FCMP(name, size, reg1, reg2, FS, E) \ - void glue(helper_, name) (CPUSPARCState *env) \ - { \ - int ret; \ - clear_float_exceptions(env); \ - if (E) { \ - ret = glue(size, _compare)(reg1, reg2, &env->fp_status); \ - } else { \ - ret = glue(size, _compare_quiet)(reg1, reg2, \ - &env->fp_status); \ - } \ - check_ieee_exceptions(env); \ - switch (ret) { \ - case float_relation_unordered: \ - env->fsr |= (FSR_FCC1 | FSR_FCC0) << FS; \ - env->fsr |= FSR_NVA; \ - break; \ - case float_relation_less: \ - env->fsr &= ~(FSR_FCC1) << FS; \ - env->fsr |= FSR_FCC0 << FS; \ - break; \ - case float_relation_greater: \ - env->fsr &= ~(FSR_FCC0) << FS; \ - env->fsr |= FSR_FCC1 << FS; \ - break; \ - default: \ - env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \ - break; \ - } \ - } -#define GEN_FCMP_T(name, size, FS, E) \ - void glue(helper_, name)(CPUSPARCState *env, size src1, size src2) \ - { \ - int ret; \ - clear_float_exceptions(env); \ - if (E) { \ - ret = glue(size, _compare)(src1, src2, &env->fp_status); \ - } else { \ - ret = glue(size, _compare_quiet)(src1, src2, \ - &env->fp_status); \ - } \ - check_ieee_exceptions(env); \ - switch (ret) { \ - case float_relation_unordered: \ - env->fsr |= (FSR_FCC1 | FSR_FCC0) << FS; \ - break; \ - case float_relation_less: \ - env->fsr &= ~(FSR_FCC1 << FS); \ - env->fsr |= FSR_FCC0 << FS; \ - break; \ - case float_relation_greater: \ - env->fsr &= ~(FSR_FCC0 << FS); \ - env->fsr |= FSR_FCC1 << FS; \ - break; \ - default: \ - env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \ - break; \ - } \ - } - -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 inline void set_fsr(CPUSPARCState *env) -{ - int rnd_mode; - - switch (env->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); -} - -void helper_ldfsr(CPUSPARCState *env, uint32_t new_fsr) -{ - env->fsr = (new_fsr & FSR_LDFSR_MASK) | (env->fsr & FSR_LDFSR_OLDMASK); - set_fsr(env); -} - -#ifdef TARGET_SPARC64 -void helper_ldxfsr(CPUSPARCState *env, uint64_t new_fsr) -{ - env->fsr = (new_fsr & FSR_LDXFSR_MASK) | (env->fsr & FSR_LDXFSR_OLDMASK); - set_fsr(env); -} -#endif diff --git a/qemu/target-sparc/gdbstub.c b/qemu/target-sparc/gdbstub.c deleted file mode 100644 index e530dc52f..000000000 --- a/qemu/target-sparc/gdbstub.c +++ /dev/null @@ -1,208 +0,0 @@ -/* - * 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 "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 -} diff --git a/qemu/target-sparc/helper.c b/qemu/target-sparc/helper.c deleted file mode 100644 index 8349cbe2c..000000000 --- a/qemu/target-sparc/helper.c +++ /dev/null @@ -1,262 +0,0 @@ -/* - * 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 "qemu/host-utils.h" -#include "exec/helper-proto.h" -#include "sysemu/sysemu.h" - -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) { - helper_raise_exception(env, TT_PRIV_INSN); - } - - 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 helper_udiv_common(CPUSPARCState *env, target_ulong a, - target_ulong b, int cc) -{ - SPARCCPU *cpu = sparc_env_get_cpu(env); - int overflow = 0; - uint64_t x0; - uint32_t x1; - - x0 = (a & 0xffffffff) | ((int64_t) (env->y) << 32); - x1 = (b & 0xffffffff); - - if (x1 == 0) { - cpu_restore_state(CPU(cpu), GETPC()); - helper_raise_exception(env, TT_DIV_ZERO); - } - - 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 helper_udiv_common(env, a, b, 0); -} - -target_ulong helper_udiv_cc(CPUSPARCState *env, target_ulong a, target_ulong b) -{ - return helper_udiv_common(env, a, b, 1); -} - -static target_ulong helper_sdiv_common(CPUSPARCState *env, target_ulong a, - target_ulong b, int cc) -{ - SPARCCPU *cpu = sparc_env_get_cpu(env); - int overflow = 0; - int64_t x0; - int32_t x1; - - x0 = (a & 0xffffffff) | ((int64_t) (env->y) << 32); - x1 = (b & 0xffffffff); - - if (x1 == 0) { - cpu_restore_state(CPU(cpu), GETPC()); - helper_raise_exception(env, TT_DIV_ZERO); - } 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 helper_sdiv_common(env, a, b, 0); -} - -target_ulong helper_sdiv_cc(CPUSPARCState *env, target_ulong a, target_ulong b) -{ - return helper_sdiv_common(env, a, b, 1); -} - -#ifdef TARGET_SPARC64 -int64_t helper_sdivx(CPUSPARCState *env, int64_t a, int64_t b) -{ - if (b == 0) { - /* Raise divide by zero trap. */ - SPARCCPU *cpu = sparc_env_get_cpu(env); - - cpu_restore_state(CPU(cpu), GETPC()); - helper_raise_exception(env, TT_DIV_ZERO); - } 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. */ - SPARCCPU *cpu = sparc_env_get_cpu(env); - - cpu_restore_state(CPU(cpu), GETPC()); - helper_raise_exception(env, TT_DIV_ZERO); - } - return a / b; -} -#endif - -target_ulong helper_taddcctv(CPUSPARCState *env, target_ulong src1, - target_ulong src2) -{ - SPARCCPU *cpu = sparc_env_get_cpu(env); - 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_restore_state(CPU(cpu), GETPC()); - helper_raise_exception(env, TT_TOVF); -} - -target_ulong helper_tsubcctv(CPUSPARCState *env, target_ulong src1, - target_ulong src2) -{ - SPARCCPU *cpu = sparc_env_get_cpu(env); - 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_restore_state(CPU(cpu), GETPC()); - helper_raise_exception(env, TT_TOVF); -} - -#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 diff --git a/qemu/target-sparc/helper.h b/qemu/target-sparc/helper.h deleted file mode 100644 index 4374f0dd2..000000000 --- a/qemu/target-sparc/helper.h +++ /dev/null @@ -1,175 +0,0 @@ -#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_2(wrpil, void, env, tl) -DEF_HELPER_2(wrpstate, void, env, tl) -DEF_HELPER_1(done, void, env) -DEF_HELPER_1(retry, void, env) -DEF_HELPER_1(flushw, void, env) -DEF_HELPER_1(saved, void, env) -DEF_HELPER_1(restored, void, env) -DEF_HELPER_1(rdccr, tl, env) -DEF_HELPER_2(wrccr, void, env, tl) -DEF_HELPER_1(rdcwp, tl, env) -DEF_HELPER_2(wrcwp, void, env, tl) -DEF_HELPER_FLAGS_2(array8, TCG_CALL_NO_RWG_SE, tl, tl, tl) -DEF_HELPER_1(popc, tl, tl) -DEF_HELPER_4(ldda_asi, void, env, tl, int, int) -DEF_HELPER_5(ldf_asi, void, env, tl, int, int, int) -DEF_HELPER_5(stf_asi, void, env, tl, int, int, int) -DEF_HELPER_5(casx_asi, tl, env, tl, tl, tl, i32) -DEF_HELPER_2(set_softint, void, env, i64) -DEF_HELPER_2(clear_softint, void, env, i64) -DEF_HELPER_2(write_softint, void, env, i64) -DEF_HELPER_2(tick_set_count, void, ptr, i64) -DEF_HELPER_3(tick_get_count, i64, env, ptr, int) -DEF_HELPER_2(tick_set_limit, void, ptr, i64) -#endif -#if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64) -DEF_HELPER_5(cas_asi, tl, env, tl, tl, tl, i32) -#endif -DEF_HELPER_3(check_align, 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_3(sdivx, s64, env, s64, s64) -DEF_HELPER_3(udivx, i64, env, i64, i64) -#endif -DEF_HELPER_3(ldqf, void, env, tl, int) -DEF_HELPER_3(stqf, void, env, tl, int) -#if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64) -DEF_HELPER_5(ld_asi, i64, env, tl, int, int, int) -DEF_HELPER_5(st_asi, void, env, tl, i64, int, int) -#endif -DEF_HELPER_2(ldfsr, void, env, i32) -DEF_HELPER_FLAGS_1(fabss, TCG_CALL_NO_RWG_SE, f32, f32) -DEF_HELPER_2(fsqrts, f32, env, f32) -DEF_HELPER_2(fsqrtd, f64, env, f64) -DEF_HELPER_3(fcmps, void, env, f32, f32) -DEF_HELPER_3(fcmpd, void, env, f64, f64) -DEF_HELPER_3(fcmpes, void, env, f32, f32) -DEF_HELPER_3(fcmped, void, env, f64, f64) -DEF_HELPER_1(fsqrtq, void, env) -DEF_HELPER_1(fcmpq, void, env) -DEF_HELPER_1(fcmpeq, void, env) -#ifdef TARGET_SPARC64 -DEF_HELPER_2(ldxfsr, void, env, i64) -DEF_HELPER_FLAGS_1(fabsd, TCG_CALL_NO_RWG_SE, f64, f64) -DEF_HELPER_3(fcmps_fcc1, void, env, f32, f32) -DEF_HELPER_3(fcmps_fcc2, void, env, f32, f32) -DEF_HELPER_3(fcmps_fcc3, void, env, f32, f32) -DEF_HELPER_3(fcmpd_fcc1, void, env, f64, f64) -DEF_HELPER_3(fcmpd_fcc2, void, env, f64, f64) -DEF_HELPER_3(fcmpd_fcc3, void, env, f64, f64) -DEF_HELPER_3(fcmpes_fcc1, void, env, f32, f32) -DEF_HELPER_3(fcmpes_fcc2, void, env, f32, f32) -DEF_HELPER_3(fcmpes_fcc3, void, env, f32, f32) -DEF_HELPER_3(fcmped_fcc1, void, env, f64, f64) -DEF_HELPER_3(fcmped_fcc2, void, env, f64, f64) -DEF_HELPER_3(fcmped_fcc3, void, env, f64, f64) -DEF_HELPER_1(fabsq, void, env) -DEF_HELPER_1(fcmpq_fcc1, void, env) -DEF_HELPER_1(fcmpq_fcc2, void, env) -DEF_HELPER_1(fcmpq_fcc3, void, env) -DEF_HELPER_1(fcmpeq_fcc1, void, env) -DEF_HELPER_1(fcmpeq_fcc2, void, env) -DEF_HELPER_1(fcmpeq_fcc3, void, env) -#endif -DEF_HELPER_2(raise_exception, noreturn, env, int) -#define F_HELPER_0_1(name) DEF_HELPER_1(f ## name, void, env) - -DEF_HELPER_3(faddd, f64, env, f64, f64) -DEF_HELPER_3(fsubd, f64, env, f64, f64) -DEF_HELPER_3(fmuld, f64, env, f64, f64) -DEF_HELPER_3(fdivd, f64, env, f64, f64) -F_HELPER_0_1(addq) -F_HELPER_0_1(subq) -F_HELPER_0_1(mulq) -F_HELPER_0_1(divq) - -DEF_HELPER_3(fadds, f32, env, f32, f32) -DEF_HELPER_3(fsubs, f32, env, f32, f32) -DEF_HELPER_3(fmuls, f32, env, f32, f32) -DEF_HELPER_3(fdivs, f32, env, f32, f32) - -DEF_HELPER_3(fsmuld, f64, env, f32, f32) -DEF_HELPER_3(fdmulq, void, env, f64, f64) - -DEF_HELPER_FLAGS_1(fnegs, TCG_CALL_NO_RWG_SE, f32, f32) -DEF_HELPER_2(fitod, f64, env, s32) -DEF_HELPER_2(fitoq, void, env, s32) - -DEF_HELPER_2(fitos, f32, env, s32) - -#ifdef TARGET_SPARC64 -DEF_HELPER_FLAGS_1(fnegd, TCG_CALL_NO_RWG_SE, f64, f64) -DEF_HELPER_1(fnegq, void, env) -DEF_HELPER_2(fxtos, f32, env, s64) -DEF_HELPER_2(fxtod, f64, env, s64) -DEF_HELPER_2(fxtoq, void, env, s64) -#endif -DEF_HELPER_2(fdtos, f32, env, f64) -DEF_HELPER_2(fstod, f64, env, f32) -DEF_HELPER_1(fqtos, f32, env) -DEF_HELPER_2(fstoq, void, env, f32) -DEF_HELPER_1(fqtod, f64, env) -DEF_HELPER_2(fdtoq, void, env, f64) -DEF_HELPER_2(fstoi, s32, env, f32) -DEF_HELPER_2(fdtoi, s32, env, f64) -DEF_HELPER_1(fqtoi, s32, env) -#ifdef TARGET_SPARC64 -DEF_HELPER_2(fstox, s64, env, f32) -DEF_HELPER_2(fdtox, s64, env, f64) -DEF_HELPER_1(fqtox, s64, env) - -DEF_HELPER_FLAGS_2(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_1(compute_C_icc, i32, env) diff --git a/qemu/target-sparc/int32_helper.c b/qemu/target-sparc/int32_helper.c deleted file mode 100644 index 09afe136e..000000000 --- a/qemu/target-sparc/int32_helper.c +++ /dev/null @@ -1,175 +0,0 @@ -/* - * 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 diff --git a/qemu/target-sparc/int64_helper.c b/qemu/target-sparc/int64_helper.c deleted file mode 100644 index 29360fa5f..000000000 --- a/qemu/target-sparc/int64_helper.c +++ /dev/null @@ -1,205 +0,0 @@ -/* - * 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); - } -} diff --git a/qemu/target-sparc/ldst_helper.c b/qemu/target-sparc/ldst_helper.c deleted file mode 100644 index 658e7d858..000000000 --- a/qemu/target-sparc/ldst_helper.c +++ /dev/null @@ -1,2456 +0,0 @@ -/* - * Helpers for loads and stores - * - * 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/cpu_ldst.h" - -//#define DEBUG_MMU -//#define DEBUG_MXCC -//#define DEBUG_UNALIGNED -//#define DEBUG_UNASSIGNED -//#define DEBUG_ASI -//#define DEBUG_CACHE_CONTROL - -#ifdef DEBUG_MMU -#define DPRINTF_MMU(fmt, ...) \ - do { printf("MMU: " fmt , ## __VA_ARGS__); } while (0) -#else -#define DPRINTF_MMU(fmt, ...) do {} while (0) -#endif - -#ifdef DEBUG_MXCC -#define DPRINTF_MXCC(fmt, ...) \ - do { printf("MXCC: " fmt , ## __VA_ARGS__); } while (0) -#else -#define DPRINTF_MXCC(fmt, ...) do {} while (0) -#endif - -#ifdef DEBUG_ASI -#define DPRINTF_ASI(fmt, ...) \ - do { printf("ASI: " fmt , ## __VA_ARGS__); } while (0) -#endif - -#ifdef DEBUG_CACHE_CONTROL -#define DPRINTF_CACHE_CONTROL(fmt, ...) \ - do { printf("CACHE_CONTROL: " fmt , ## __VA_ARGS__); } while (0) -#else -#define DPRINTF_CACHE_CONTROL(fmt, ...) do {} while (0) -#endif - -#ifdef TARGET_SPARC64 -#ifndef TARGET_ABI32 -#define AM_CHECK(env1) ((env1)->pstate & PS_AM) -#else -#define AM_CHECK(env1) (1) -#endif -#endif - -#define QT0 (env->qt0) -#define QT1 (env->qt1) - -#if defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY) -/* Calculates TSB pointer value for fault page size 8k or 64k */ -static uint64_t ultrasparc_tsb_pointer(uint64_t tsb_register, - uint64_t tag_access_register, - int page_size) -{ - uint64_t tsb_base = tsb_register & ~0x1fffULL; - int tsb_split = (tsb_register & 0x1000ULL) ? 1 : 0; - int tsb_size = tsb_register & 0xf; - - /* discard lower 13 bits which hold tag access context */ - uint64_t tag_access_va = tag_access_register & ~0x1fffULL; - - /* now reorder bits */ - uint64_t tsb_base_mask = ~0x1fffULL; - uint64_t va = tag_access_va; - - /* move va bits to correct position */ - if (page_size == 8*1024) { - va >>= 9; - } else if (page_size == 64*1024) { - va >>= 12; - } - - if (tsb_size) { - tsb_base_mask <<= tsb_size; - } - - /* calculate tsb_base mask and adjust va if split is in use */ - if (tsb_split) { - if (page_size == 8*1024) { - va &= ~(1ULL << (13 + tsb_size)); - } else if (page_size == 64*1024) { - va |= (1ULL << (13 + tsb_size)); - } - tsb_base_mask <<= 1; - } - - return ((tsb_base & tsb_base_mask) | (va & ~tsb_base_mask)) & ~0xfULL; -} - -/* Calculates tag target register value by reordering bits - in tag access register */ -static uint64_t ultrasparc_tag_target(uint64_t tag_access_register) -{ - return ((tag_access_register & 0x1fff) << 48) | (tag_access_register >> 22); -} - -static void replace_tlb_entry(SparcTLBEntry *tlb, - uint64_t tlb_tag, uint64_t tlb_tte, - CPUSPARCState *env1) -{ - target_ulong mask, size, va, offset; - - /* flush page range if translation is valid */ - if (TTE_IS_VALID(tlb->tte)) { - CPUState *cs = CPU(sparc_env_get_cpu(env1)); - - mask = 0xffffffffffffe000ULL; - mask <<= 3 * ((tlb->tte >> 61) & 3); - size = ~mask + 1; - - va = tlb->tag & mask; - - for (offset = 0; offset < size; offset += TARGET_PAGE_SIZE) { - tlb_flush_page(cs, va + offset); - } - } - - tlb->tag = tlb_tag; - tlb->tte = tlb_tte; -} - -static void demap_tlb(SparcTLBEntry *tlb, target_ulong demap_addr, - const char *strmmu, CPUSPARCState *env1) -{ - unsigned int i; - target_ulong mask; - uint64_t context; - - int is_demap_context = (demap_addr >> 6) & 1; - - /* demap context */ - switch ((demap_addr >> 4) & 3) { - case 0: /* primary */ - context = env1->dmmu.mmu_primary_context; - break; - case 1: /* secondary */ - context = env1->dmmu.mmu_secondary_context; - break; - case 2: /* nucleus */ - context = 0; - break; - case 3: /* reserved */ - default: - return; - } - - for (i = 0; i < 64; i++) { - if (TTE_IS_VALID(tlb[i].tte)) { - - if (is_demap_context) { - /* will remove non-global entries matching context value */ - if (TTE_IS_GLOBAL(tlb[i].tte) || - !tlb_compare_context(&tlb[i], context)) { - continue; - } - } else { - /* demap page - will remove any entry matching VA */ - mask = 0xffffffffffffe000ULL; - mask <<= 3 * ((tlb[i].tte >> 61) & 3); - - if (!compare_masked(demap_addr, tlb[i].tag, mask)) { - continue; - } - - /* entry should be global or matching context value */ - if (!TTE_IS_GLOBAL(tlb[i].tte) && - !tlb_compare_context(&tlb[i], context)) { - continue; - } - } - - replace_tlb_entry(&tlb[i], 0, 0, env1); -#ifdef DEBUG_MMU - DPRINTF_MMU("%s demap invalidated entry [%02u]\n", strmmu, i); - dump_mmu(stdout, fprintf, env1); -#endif - } - } -} - -static void replace_tlb_1bit_lru(SparcTLBEntry *tlb, - uint64_t tlb_tag, uint64_t tlb_tte, - const char *strmmu, CPUSPARCState *env1) -{ - unsigned int i, replace_used; - - /* Try replacing invalid entry */ - for (i = 0; i < 64; i++) { - if (!TTE_IS_VALID(tlb[i].tte)) { - replace_tlb_entry(&tlb[i], tlb_tag, tlb_tte, env1); -#ifdef DEBUG_MMU - DPRINTF_MMU("%s lru replaced invalid entry [%i]\n", strmmu, i); - dump_mmu(stdout, fprintf, env1); -#endif - return; - } - } - - /* All entries are valid, try replacing unlocked entry */ - - for (replace_used = 0; replace_used < 2; ++replace_used) { - - /* Used entries are not replaced on first pass */ - - for (i = 0; i < 64; i++) { - if (!TTE_IS_LOCKED(tlb[i].tte) && !TTE_IS_USED(tlb[i].tte)) { - - replace_tlb_entry(&tlb[i], tlb_tag, tlb_tte, env1); -#ifdef DEBUG_MMU - DPRINTF_MMU("%s lru replaced unlocked %s entry [%i]\n", - strmmu, (replace_used ? "used" : "unused"), i); - dump_mmu(stdout, fprintf, env1); -#endif - return; - } - } - - /* Now reset used bit and search for unused entries again */ - - for (i = 0; i < 64; i++) { - TTE_SET_UNUSED(tlb[i].tte); - } - } - -#ifdef DEBUG_MMU - DPRINTF_MMU("%s lru replacement failed: no entries available\n", strmmu); -#endif - /* error state? */ -} - -#endif - -#if defined(TARGET_SPARC64) || defined(CONFIG_USER_ONLY) -static inline target_ulong address_mask(CPUSPARCState *env1, target_ulong addr) -{ -#ifdef TARGET_SPARC64 - if (AM_CHECK(env1)) { - addr &= 0xffffffffULL; - } -#endif - return addr; -} -#endif - -#ifdef TARGET_SPARC64 -/* returns true if access using this ASI is to have address translated by MMU - otherwise access is to raw physical address */ -/* TODO: check sparc32 bits */ -static inline int is_translating_asi(int asi) -{ - /* Ultrasparc IIi translating asi - - note this list is defined by cpu implementation - */ - switch (asi) { - case 0x04 ... 0x11: - case 0x16 ... 0x19: - case 0x1E ... 0x1F: - case 0x24 ... 0x2C: - case 0x70 ... 0x73: - case 0x78 ... 0x79: - case 0x80 ... 0xFF: - return 1; - - default: - return 0; - } -} - -static inline target_ulong asi_address_mask(CPUSPARCState *env, - int asi, target_ulong addr) -{ - if (is_translating_asi(asi)) { - return address_mask(env, addr); - } else { - return addr; - } -} -#endif - -void helper_check_align(CPUSPARCState *env, target_ulong addr, uint32_t align) -{ - if (addr & align) { -#ifdef DEBUG_UNALIGNED - printf("Unaligned access to 0x" TARGET_FMT_lx " from 0x" TARGET_FMT_lx - "\n", addr, env->pc); -#endif - helper_raise_exception(env, TT_UNALIGNED); - } -} - -#if !defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY) && \ - defined(DEBUG_MXCC) -static void dump_mxcc(CPUSPARCState *env) -{ - printf("mxccdata: %016" PRIx64 " %016" PRIx64 " %016" PRIx64 " %016" PRIx64 - "\n", - env->mxccdata[0], env->mxccdata[1], - env->mxccdata[2], env->mxccdata[3]); - printf("mxccregs: %016" PRIx64 " %016" PRIx64 " %016" PRIx64 " %016" PRIx64 - "\n" - " %016" PRIx64 " %016" PRIx64 " %016" PRIx64 " %016" PRIx64 - "\n", - env->mxccregs[0], env->mxccregs[1], - env->mxccregs[2], env->mxccregs[3], - env->mxccregs[4], env->mxccregs[5], - env->mxccregs[6], env->mxccregs[7]); -} -#endif - -#if (defined(TARGET_SPARC64) || !defined(CONFIG_USER_ONLY)) \ - && defined(DEBUG_ASI) -static void dump_asi(const char *txt, target_ulong addr, int asi, int size, - uint64_t r1) -{ - switch (size) { - case 1: - DPRINTF_ASI("%s "TARGET_FMT_lx " asi 0x%02x = %02" PRIx64 "\n", txt, - addr, asi, r1 & 0xff); - break; - case 2: - DPRINTF_ASI("%s "TARGET_FMT_lx " asi 0x%02x = %04" PRIx64 "\n", txt, - addr, asi, r1 & 0xffff); - break; - case 4: - DPRINTF_ASI("%s "TARGET_FMT_lx " asi 0x%02x = %08" PRIx64 "\n", txt, - addr, asi, r1 & 0xffffffff); - break; - case 8: - DPRINTF_ASI("%s "TARGET_FMT_lx " asi 0x%02x = %016" PRIx64 "\n", txt, - addr, asi, r1); - break; - } -} -#endif - -#ifndef TARGET_SPARC64 -#ifndef CONFIG_USER_ONLY - - -/* Leon3 cache control */ - -static void leon3_cache_control_st(CPUSPARCState *env, target_ulong addr, - uint64_t val, int size) -{ - DPRINTF_CACHE_CONTROL("st addr:%08x, val:%" PRIx64 ", size:%d\n", - addr, val, size); - - if (size != 4) { - DPRINTF_CACHE_CONTROL("32bits only\n"); - return; - } - - switch (addr) { - case 0x00: /* Cache control */ - - /* These values must always be read as zeros */ - val &= ~CACHE_CTRL_FD; - val &= ~CACHE_CTRL_FI; - val &= ~CACHE_CTRL_IB; - val &= ~CACHE_CTRL_IP; - val &= ~CACHE_CTRL_DP; - - env->cache_control = val; - break; - case 0x04: /* Instruction cache configuration */ - case 0x08: /* Data cache configuration */ - /* Read Only */ - break; - default: - DPRINTF_CACHE_CONTROL("write unknown register %08x\n", addr); - break; - }; -} - -static uint64_t leon3_cache_control_ld(CPUSPARCState *env, target_ulong addr, - int size) -{ - uint64_t ret = 0; - - if (size != 4) { - DPRINTF_CACHE_CONTROL("32bits only\n"); - return 0; - } - - switch (addr) { - case 0x00: /* Cache control */ - ret = env->cache_control; - break; - - /* Configuration registers are read and only always keep those - predefined values */ - - case 0x04: /* Instruction cache configuration */ - ret = 0x10220000; - break; - case 0x08: /* Data cache configuration */ - ret = 0x18220000; - break; - default: - DPRINTF_CACHE_CONTROL("read unknown register %08x\n", addr); - break; - }; - DPRINTF_CACHE_CONTROL("ld addr:%08x, ret:0x%" PRIx64 ", size:%d\n", - addr, ret, size); - return ret; -} - -uint64_t helper_ld_asi(CPUSPARCState *env, target_ulong addr, int asi, int size, - int sign) -{ - CPUState *cs = CPU(sparc_env_get_cpu(env)); - uint64_t ret = 0; -#if defined(DEBUG_MXCC) || defined(DEBUG_ASI) - uint32_t last_addr = addr; -#endif - - helper_check_align(env, addr, size - 1); - switch (asi) { - case 2: /* SuperSparc MXCC registers and Leon3 cache control */ - switch (addr) { - case 0x00: /* Leon3 Cache Control */ - case 0x08: /* Leon3 Instruction Cache config */ - case 0x0C: /* Leon3 Date Cache config */ - if (env->def->features & CPU_FEATURE_CACHE_CTRL) { - ret = leon3_cache_control_ld(env, addr, size); - } - break; - case 0x01c00a00: /* MXCC control register */ - if (size == 8) { - ret = env->mxccregs[3]; - } else { - qemu_log_mask(LOG_UNIMP, - "%08x: unimplemented access size: %d\n", addr, - size); - } - break; - case 0x01c00a04: /* MXCC control register */ - if (size == 4) { - ret = env->mxccregs[3]; - } else { - qemu_log_mask(LOG_UNIMP, - "%08x: unimplemented access size: %d\n", addr, - size); - } - break; - case 0x01c00c00: /* Module reset register */ - if (size == 8) { - ret = env->mxccregs[5]; - /* should we do something here? */ - } else { - qemu_log_mask(LOG_UNIMP, - "%08x: unimplemented access size: %d\n", addr, - size); - } - break; - case 0x01c00f00: /* MBus port address register */ - if (size == 8) { - ret = env->mxccregs[7]; - } else { - qemu_log_mask(LOG_UNIMP, - "%08x: unimplemented access size: %d\n", addr, - size); - } - break; - default: - qemu_log_mask(LOG_UNIMP, - "%08x: unimplemented address, size: %d\n", addr, - size); - break; - } - DPRINTF_MXCC("asi = %d, size = %d, sign = %d, " - "addr = %08x -> ret = %" PRIx64 "," - "addr = %08x\n", asi, size, sign, last_addr, ret, addr); -#ifdef DEBUG_MXCC - dump_mxcc(env); -#endif - break; - case 3: /* MMU probe */ - case 0x18: /* LEON3 MMU probe */ - { - int mmulev; - - mmulev = (addr >> 8) & 15; - if (mmulev > 4) { - ret = 0; - } else { - ret = mmu_probe(env, addr, mmulev); - } - DPRINTF_MMU("mmu_probe: 0x%08x (lev %d) -> 0x%08" PRIx64 "\n", - addr, mmulev, ret); - } - break; - case 4: /* read MMU regs */ - case 0x19: /* LEON3 read MMU regs */ - { - int reg = (addr >> 8) & 0x1f; - - ret = env->mmuregs[reg]; - if (reg == 3) { /* Fault status cleared on read */ - env->mmuregs[3] = 0; - } else if (reg == 0x13) { /* Fault status read */ - ret = env->mmuregs[3]; - } else if (reg == 0x14) { /* Fault address read */ - ret = env->mmuregs[4]; - } - DPRINTF_MMU("mmu_read: reg[%d] = 0x%08" PRIx64 "\n", reg, ret); - } - break; - case 5: /* Turbosparc ITLB Diagnostic */ - case 6: /* Turbosparc DTLB Diagnostic */ - case 7: /* Turbosparc IOTLB Diagnostic */ - break; - case 9: /* Supervisor code access */ - switch (size) { - case 1: - ret = cpu_ldub_code(env, addr); - break; - case 2: - ret = cpu_lduw_code(env, addr); - break; - default: - case 4: - ret = cpu_ldl_code(env, addr); - break; - case 8: - ret = cpu_ldq_code(env, addr); - break; - } - break; - case 0xa: /* User data access */ - switch (size) { - case 1: - ret = cpu_ldub_user(env, addr); - break; - case 2: - ret = cpu_lduw_user(env, addr); - break; - default: - case 4: - ret = cpu_ldl_user(env, addr); - break; - case 8: - ret = cpu_ldq_user(env, addr); - break; - } - break; - case 0xb: /* Supervisor data access */ - case 0x80: - switch (size) { - case 1: - ret = cpu_ldub_kernel(env, addr); - break; - case 2: - ret = cpu_lduw_kernel(env, addr); - break; - default: - case 4: - ret = cpu_ldl_kernel(env, addr); - break; - case 8: - ret = cpu_ldq_kernel(env, addr); - break; - } - break; - case 0xc: /* I-cache tag */ - case 0xd: /* I-cache data */ - case 0xe: /* D-cache tag */ - case 0xf: /* D-cache data */ - break; - case 0x20: /* MMU passthrough */ - case 0x1c: /* LEON MMU passthrough */ - switch (size) { - case 1: - ret = ldub_phys(cs->as, addr); - break; - case 2: - ret = lduw_phys(cs->as, addr); - break; - default: - case 4: - ret = ldl_phys(cs->as, addr); - break; - case 8: - ret = ldq_phys(cs->as, addr); - break; - } - break; - case 0x21 ... 0x2f: /* MMU passthrough, 0x100000000 to 0xfffffffff */ - switch (size) { - case 1: - ret = ldub_phys(cs->as, (hwaddr)addr - | ((hwaddr)(asi & 0xf) << 32)); - break; - case 2: - ret = lduw_phys(cs->as, (hwaddr)addr - | ((hwaddr)(asi & 0xf) << 32)); - break; - default: - case 4: - ret = ldl_phys(cs->as, (hwaddr)addr - | ((hwaddr)(asi & 0xf) << 32)); - break; - case 8: - ret = ldq_phys(cs->as, (hwaddr)addr - | ((hwaddr)(asi & 0xf) << 32)); - break; - } - break; - case 0x30: /* Turbosparc secondary cache diagnostic */ - case 0x31: /* Turbosparc RAM snoop */ - case 0x32: /* Turbosparc page table descriptor diagnostic */ - case 0x39: /* data cache diagnostic register */ - ret = 0; - break; - case 0x38: /* SuperSPARC MMU Breakpoint Control Registers */ - { - int reg = (addr >> 8) & 3; - - switch (reg) { - case 0: /* Breakpoint Value (Addr) */ - ret = env->mmubpregs[reg]; - break; - case 1: /* Breakpoint Mask */ - ret = env->mmubpregs[reg]; - break; - case 2: /* Breakpoint Control */ - ret = env->mmubpregs[reg]; - break; - case 3: /* Breakpoint Status */ - ret = env->mmubpregs[reg]; - env->mmubpregs[reg] = 0ULL; - break; - } - DPRINTF_MMU("read breakpoint reg[%d] 0x%016" PRIx64 "\n", reg, - ret); - } - break; - case 0x49: /* SuperSPARC MMU Counter Breakpoint Value */ - ret = env->mmubpctrv; - break; - case 0x4a: /* SuperSPARC MMU Counter Breakpoint Control */ - ret = env->mmubpctrc; - break; - case 0x4b: /* SuperSPARC MMU Counter Breakpoint Status */ - ret = env->mmubpctrs; - break; - case 0x4c: /* SuperSPARC MMU Breakpoint Action */ - ret = env->mmubpaction; - break; - case 8: /* User code access, XXX */ - default: - cpu_unassigned_access(cs, addr, false, false, asi, size); - ret = 0; - break; - } - if (sign) { - switch (size) { - case 1: - ret = (int8_t) ret; - break; - case 2: - ret = (int16_t) ret; - break; - case 4: - ret = (int32_t) ret; - break; - default: - break; - } - } -#ifdef DEBUG_ASI - dump_asi("read ", last_addr, asi, size, ret); -#endif - return ret; -} - -void helper_st_asi(CPUSPARCState *env, target_ulong addr, uint64_t val, int asi, - int size) -{ - SPARCCPU *cpu = sparc_env_get_cpu(env); - CPUState *cs = CPU(cpu); - - helper_check_align(env, addr, size - 1); - switch (asi) { - case 2: /* SuperSparc MXCC registers and Leon3 cache control */ - switch (addr) { - case 0x00: /* Leon3 Cache Control */ - case 0x08: /* Leon3 Instruction Cache config */ - case 0x0C: /* Leon3 Date Cache config */ - if (env->def->features & CPU_FEATURE_CACHE_CTRL) { - leon3_cache_control_st(env, addr, val, size); - } - break; - - case 0x01c00000: /* MXCC stream data register 0 */ - if (size == 8) { - env->mxccdata[0] = val; - } else { - qemu_log_mask(LOG_UNIMP, - "%08x: unimplemented access size: %d\n", addr, - size); - } - break; - case 0x01c00008: /* MXCC stream data register 1 */ - if (size == 8) { - env->mxccdata[1] = val; - } else { - qemu_log_mask(LOG_UNIMP, - "%08x: unimplemented access size: %d\n", addr, - size); - } - break; - case 0x01c00010: /* MXCC stream data register 2 */ - if (size == 8) { - env->mxccdata[2] = val; - } else { - qemu_log_mask(LOG_UNIMP, - "%08x: unimplemented access size: %d\n", addr, - size); - } - break; - case 0x01c00018: /* MXCC stream data register 3 */ - if (size == 8) { - env->mxccdata[3] = val; - } else { - qemu_log_mask(LOG_UNIMP, - "%08x: unimplemented access size: %d\n", addr, - size); - } - break; - case 0x01c00100: /* MXCC stream source */ - if (size == 8) { - env->mxccregs[0] = val; - } else { - qemu_log_mask(LOG_UNIMP, - "%08x: unimplemented access size: %d\n", addr, - size); - } - env->mxccdata[0] = ldq_phys(cs->as, - (env->mxccregs[0] & 0xffffffffULL) + - 0); - env->mxccdata[1] = ldq_phys(cs->as, - (env->mxccregs[0] & 0xffffffffULL) + - 8); - env->mxccdata[2] = ldq_phys(cs->as, - (env->mxccregs[0] & 0xffffffffULL) + - 16); - env->mxccdata[3] = ldq_phys(cs->as, - (env->mxccregs[0] & 0xffffffffULL) + - 24); - break; - case 0x01c00200: /* MXCC stream destination */ - if (size == 8) { - env->mxccregs[1] = val; - } else { - qemu_log_mask(LOG_UNIMP, - "%08x: unimplemented access size: %d\n", addr, - size); - } - stq_phys(cs->as, (env->mxccregs[1] & 0xffffffffULL) + 0, - env->mxccdata[0]); - stq_phys(cs->as, (env->mxccregs[1] & 0xffffffffULL) + 8, - env->mxccdata[1]); - stq_phys(cs->as, (env->mxccregs[1] & 0xffffffffULL) + 16, - env->mxccdata[2]); - stq_phys(cs->as, (env->mxccregs[1] & 0xffffffffULL) + 24, - env->mxccdata[3]); - break; - case 0x01c00a00: /* MXCC control register */ - if (size == 8) { - env->mxccregs[3] = val; - } else { - qemu_log_mask(LOG_UNIMP, - "%08x: unimplemented access size: %d\n", addr, - size); - } - break; - case 0x01c00a04: /* MXCC control register */ - if (size == 4) { - env->mxccregs[3] = (env->mxccregs[3] & 0xffffffff00000000ULL) - | val; - } else { - qemu_log_mask(LOG_UNIMP, - "%08x: unimplemented access size: %d\n", addr, - size); - } - break; - case 0x01c00e00: /* MXCC error register */ - /* writing a 1 bit clears the error */ - if (size == 8) { - env->mxccregs[6] &= ~val; - } else { - qemu_log_mask(LOG_UNIMP, - "%08x: unimplemented access size: %d\n", addr, - size); - } - break; - case 0x01c00f00: /* MBus port address register */ - if (size == 8) { - env->mxccregs[7] = val; - } else { - qemu_log_mask(LOG_UNIMP, - "%08x: unimplemented access size: %d\n", addr, - size); - } - break; - default: - qemu_log_mask(LOG_UNIMP, - "%08x: unimplemented address, size: %d\n", addr, - size); - break; - } - DPRINTF_MXCC("asi = %d, size = %d, addr = %08x, val = %" PRIx64 "\n", - asi, size, addr, val); -#ifdef DEBUG_MXCC - dump_mxcc(env); -#endif - break; - case 3: /* MMU flush */ - case 0x18: /* LEON3 MMU flush */ - { - int mmulev; - - mmulev = (addr >> 8) & 15; - DPRINTF_MMU("mmu flush level %d\n", mmulev); - switch (mmulev) { - case 0: /* flush page */ - tlb_flush_page(CPU(cpu), addr & 0xfffff000); - break; - case 1: /* flush segment (256k) */ - case 2: /* flush region (16M) */ - case 3: /* flush context (4G) */ - case 4: /* flush entire */ - tlb_flush(CPU(cpu), 1); - break; - default: - break; - } -#ifdef DEBUG_MMU - dump_mmu(stdout, fprintf, env); -#endif - } - break; - case 4: /* write MMU regs */ - case 0x19: /* LEON3 write MMU regs */ - { - int reg = (addr >> 8) & 0x1f; - uint32_t oldreg; - - oldreg = env->mmuregs[reg]; - switch (reg) { - case 0: /* Control Register */ - env->mmuregs[reg] = (env->mmuregs[reg] & 0xff000000) | - (val & 0x00ffffff); - /* Mappings generated during no-fault mode or MMU - disabled mode are invalid in normal mode */ - if ((oldreg & (MMU_E | MMU_NF | env->def->mmu_bm)) != - (env->mmuregs[reg] & (MMU_E | MMU_NF | env->def->mmu_bm))) { - tlb_flush(CPU(cpu), 1); - } - break; - case 1: /* Context Table Pointer Register */ - env->mmuregs[reg] = val & env->def->mmu_ctpr_mask; - break; - case 2: /* Context Register */ - env->mmuregs[reg] = val & env->def->mmu_cxr_mask; - if (oldreg != env->mmuregs[reg]) { - /* we flush when the MMU context changes because - QEMU has no MMU context support */ - tlb_flush(CPU(cpu), 1); - } - break; - case 3: /* Synchronous Fault Status Register with Clear */ - case 4: /* Synchronous Fault Address Register */ - break; - case 0x10: /* TLB Replacement Control Register */ - env->mmuregs[reg] = val & env->def->mmu_trcr_mask; - break; - case 0x13: /* Synchronous Fault Status Register with Read - and Clear */ - env->mmuregs[3] = val & env->def->mmu_sfsr_mask; - break; - case 0x14: /* Synchronous Fault Address Register */ - env->mmuregs[4] = val; - break; - default: - env->mmuregs[reg] = val; - break; - } - if (oldreg != env->mmuregs[reg]) { - DPRINTF_MMU("mmu change reg[%d]: 0x%08x -> 0x%08x\n", - reg, oldreg, env->mmuregs[reg]); - } -#ifdef DEBUG_MMU - dump_mmu(stdout, fprintf, env); -#endif - } - break; - case 5: /* Turbosparc ITLB Diagnostic */ - case 6: /* Turbosparc DTLB Diagnostic */ - case 7: /* Turbosparc IOTLB Diagnostic */ - break; - case 0xa: /* User data access */ - switch (size) { - case 1: - cpu_stb_user(env, addr, val); - break; - case 2: - cpu_stw_user(env, addr, val); - break; - default: - case 4: - cpu_stl_user(env, addr, val); - break; - case 8: - cpu_stq_user(env, addr, val); - break; - } - break; - case 0xb: /* Supervisor data access */ - case 0x80: - switch (size) { - case 1: - cpu_stb_kernel(env, addr, val); - break; - case 2: - cpu_stw_kernel(env, addr, val); - break; - default: - case 4: - cpu_stl_kernel(env, addr, val); - break; - case 8: - cpu_stq_kernel(env, addr, val); - break; - } - break; - case 0xc: /* I-cache tag */ - case 0xd: /* I-cache data */ - case 0xe: /* D-cache tag */ - case 0xf: /* D-cache data */ - case 0x10: /* I/D-cache flush page */ - case 0x11: /* I/D-cache flush segment */ - case 0x12: /* I/D-cache flush region */ - case 0x13: /* I/D-cache flush context */ - case 0x14: /* I/D-cache flush user */ - break; - case 0x17: /* Block copy, sta access */ - { - /* val = src - addr = dst - copy 32 bytes */ - unsigned int i; - uint32_t src = val & ~3, dst = addr & ~3, temp; - - for (i = 0; i < 32; i += 4, src += 4, dst += 4) { - temp = cpu_ldl_kernel(env, src); - cpu_stl_kernel(env, dst, temp); - } - } - break; - case 0x1f: /* Block fill, stda access */ - { - /* addr = dst - fill 32 bytes with val */ - unsigned int i; - uint32_t dst = addr & 7; - - for (i = 0; i < 32; i += 8, dst += 8) { - cpu_stq_kernel(env, dst, val); - } - } - break; - case 0x20: /* MMU passthrough */ - case 0x1c: /* LEON MMU passthrough */ - { - switch (size) { - case 1: - stb_phys(cs->as, addr, val); - break; - case 2: - stw_phys(cs->as, addr, val); - break; - case 4: - default: - stl_phys(cs->as, addr, val); - break; - case 8: - stq_phys(cs->as, addr, val); - break; - } - } - break; - case 0x21 ... 0x2f: /* MMU passthrough, 0x100000000 to 0xfffffffff */ - { - switch (size) { - case 1: - stb_phys(cs->as, (hwaddr)addr - | ((hwaddr)(asi & 0xf) << 32), val); - break; - case 2: - stw_phys(cs->as, (hwaddr)addr - | ((hwaddr)(asi & 0xf) << 32), val); - break; - case 4: - default: - stl_phys(cs->as, (hwaddr)addr - | ((hwaddr)(asi & 0xf) << 32), val); - break; - case 8: - stq_phys(cs->as, (hwaddr)addr - | ((hwaddr)(asi & 0xf) << 32), val); - break; - } - } - break; - case 0x30: /* store buffer tags or Turbosparc secondary cache diagnostic */ - case 0x31: /* store buffer data, Ross RT620 I-cache flush or - Turbosparc snoop RAM */ - case 0x32: /* store buffer control or Turbosparc page table - descriptor diagnostic */ - case 0x36: /* I-cache flash clear */ - case 0x37: /* D-cache flash clear */ - break; - case 0x38: /* SuperSPARC MMU Breakpoint Control Registers*/ - { - int reg = (addr >> 8) & 3; - - switch (reg) { - case 0: /* Breakpoint Value (Addr) */ - env->mmubpregs[reg] = (val & 0xfffffffffULL); - break; - case 1: /* Breakpoint Mask */ - env->mmubpregs[reg] = (val & 0xfffffffffULL); - break; - case 2: /* Breakpoint Control */ - env->mmubpregs[reg] = (val & 0x7fULL); - break; - case 3: /* Breakpoint Status */ - env->mmubpregs[reg] = (val & 0xfULL); - break; - } - DPRINTF_MMU("write breakpoint reg[%d] 0x%016x\n", reg, - env->mmuregs[reg]); - } - break; - case 0x49: /* SuperSPARC MMU Counter Breakpoint Value */ - env->mmubpctrv = val & 0xffffffff; - break; - case 0x4a: /* SuperSPARC MMU Counter Breakpoint Control */ - env->mmubpctrc = val & 0x3; - break; - case 0x4b: /* SuperSPARC MMU Counter Breakpoint Status */ - env->mmubpctrs = val & 0x3; - break; - case 0x4c: /* SuperSPARC MMU Breakpoint Action */ - env->mmubpaction = val & 0x1fff; - break; - case 8: /* User code access, XXX */ - case 9: /* Supervisor code access, XXX */ - default: - cpu_unassigned_access(CPU(sparc_env_get_cpu(env)), - addr, true, false, asi, size); - break; - } -#ifdef DEBUG_ASI - dump_asi("write", addr, asi, size, val); -#endif -} - -#endif /* CONFIG_USER_ONLY */ -#else /* TARGET_SPARC64 */ - -#ifdef CONFIG_USER_ONLY -uint64_t helper_ld_asi(CPUSPARCState *env, target_ulong addr, int asi, int size, - int sign) -{ - uint64_t ret = 0; -#if defined(DEBUG_ASI) - target_ulong last_addr = addr; -#endif - - if (asi < 0x80) { - helper_raise_exception(env, TT_PRIV_ACT); - } - - helper_check_align(env, addr, size - 1); - addr = asi_address_mask(env, asi, addr); - - switch (asi) { - case 0x82: /* Primary no-fault */ - case 0x8a: /* Primary no-fault LE */ - if (page_check_range(addr, size, PAGE_READ) == -1) { -#ifdef DEBUG_ASI - dump_asi("read ", last_addr, asi, size, ret); -#endif - return 0; - } - /* Fall through */ - case 0x80: /* Primary */ - case 0x88: /* Primary LE */ - { - switch (size) { - case 1: - ret = cpu_ldub_data(env, addr); - break; - case 2: - ret = cpu_lduw_data(env, addr); - break; - case 4: - ret = cpu_ldl_data(env, addr); - break; - default: - case 8: - ret = cpu_ldq_data(env, addr); - break; - } - } - break; - case 0x83: /* Secondary no-fault */ - case 0x8b: /* Secondary no-fault LE */ - if (page_check_range(addr, size, PAGE_READ) == -1) { -#ifdef DEBUG_ASI - dump_asi("read ", last_addr, asi, size, ret); -#endif - return 0; - } - /* Fall through */ - case 0x81: /* Secondary */ - case 0x89: /* Secondary LE */ - /* XXX */ - break; - default: - break; - } - - /* Convert from little endian */ - switch (asi) { - case 0x88: /* Primary LE */ - case 0x89: /* Secondary LE */ - case 0x8a: /* Primary no-fault LE */ - case 0x8b: /* Secondary no-fault LE */ - switch (size) { - case 2: - ret = bswap16(ret); - break; - case 4: - ret = bswap32(ret); - break; - case 8: - ret = bswap64(ret); - break; - default: - break; - } - default: - break; - } - - /* Convert to signed number */ - if (sign) { - switch (size) { - case 1: - ret = (int8_t) ret; - break; - case 2: - ret = (int16_t) ret; - break; - case 4: - ret = (int32_t) ret; - break; - default: - break; - } - } -#ifdef DEBUG_ASI - dump_asi("read ", last_addr, asi, size, ret); -#endif - return ret; -} - -void helper_st_asi(CPUSPARCState *env, target_ulong addr, target_ulong val, - int asi, int size) -{ -#ifdef DEBUG_ASI - dump_asi("write", addr, asi, size, val); -#endif - if (asi < 0x80) { - helper_raise_exception(env, TT_PRIV_ACT); - } - - helper_check_align(env, addr, size - 1); - addr = asi_address_mask(env, asi, addr); - - /* Convert to little endian */ - switch (asi) { - case 0x88: /* Primary LE */ - case 0x89: /* Secondary LE */ - switch (size) { - case 2: - val = bswap16(val); - break; - case 4: - val = bswap32(val); - break; - case 8: - val = bswap64(val); - break; - default: - break; - } - default: - break; - } - - switch (asi) { - case 0x80: /* Primary */ - case 0x88: /* Primary LE */ - { - switch (size) { - case 1: - cpu_stb_data(env, addr, val); - break; - case 2: - cpu_stw_data(env, addr, val); - break; - case 4: - cpu_stl_data(env, addr, val); - break; - case 8: - default: - cpu_stq_data(env, addr, val); - break; - } - } - break; - case 0x81: /* Secondary */ - case 0x89: /* Secondary LE */ - /* XXX */ - return; - - case 0x82: /* Primary no-fault, RO */ - case 0x83: /* Secondary no-fault, RO */ - case 0x8a: /* Primary no-fault LE, RO */ - case 0x8b: /* Secondary no-fault LE, RO */ - default: - helper_raise_exception(env, TT_DATA_ACCESS); - return; - } -} - -#else /* CONFIG_USER_ONLY */ - -uint64_t helper_ld_asi(CPUSPARCState *env, target_ulong addr, int asi, int size, - int sign) -{ - CPUState *cs = CPU(sparc_env_get_cpu(env)); - uint64_t ret = 0; -#if defined(DEBUG_ASI) - target_ulong last_addr = addr; -#endif - - asi &= 0xff; - - if ((asi < 0x80 && (env->pstate & PS_PRIV) == 0) - || (cpu_has_hypervisor(env) - && asi >= 0x30 && asi < 0x80 - && !(env->hpstate & HS_PRIV))) { - helper_raise_exception(env, TT_PRIV_ACT); - } - - helper_check_align(env, addr, size - 1); - addr = asi_address_mask(env, asi, addr); - - /* process nonfaulting loads first */ - if ((asi & 0xf6) == 0x82) { - int mmu_idx; - - /* secondary space access has lowest asi bit equal to 1 */ - if (env->pstate & PS_PRIV) { - mmu_idx = (asi & 1) ? MMU_KERNEL_SECONDARY_IDX : MMU_KERNEL_IDX; - } else { - mmu_idx = (asi & 1) ? MMU_USER_SECONDARY_IDX : MMU_USER_IDX; - } - - if (cpu_get_phys_page_nofault(env, addr, mmu_idx) == -1ULL) { -#ifdef DEBUG_ASI - dump_asi("read ", last_addr, asi, size, ret); -#endif - /* env->exception_index is set in get_physical_address_data(). */ - helper_raise_exception(env, cs->exception_index); - } - - /* convert nonfaulting load ASIs to normal load ASIs */ - asi &= ~0x02; - } - - switch (asi) { - case 0x10: /* As if user primary */ - case 0x11: /* As if user secondary */ - case 0x18: /* As if user primary LE */ - case 0x19: /* As if user secondary LE */ - case 0x80: /* Primary */ - case 0x81: /* Secondary */ - case 0x88: /* Primary LE */ - case 0x89: /* Secondary LE */ - case 0xe2: /* UA2007 Primary block init */ - case 0xe3: /* UA2007 Secondary block init */ - if ((asi & 0x80) && (env->pstate & PS_PRIV)) { - if (cpu_hypervisor_mode(env)) { - switch (size) { - case 1: - ret = cpu_ldub_hypv(env, addr); - break; - case 2: - ret = cpu_lduw_hypv(env, addr); - break; - case 4: - ret = cpu_ldl_hypv(env, addr); - break; - default: - case 8: - ret = cpu_ldq_hypv(env, addr); - break; - } - } else { - /* secondary space access has lowest asi bit equal to 1 */ - if (asi & 1) { - switch (size) { - case 1: - ret = cpu_ldub_kernel_secondary(env, addr); - break; - case 2: - ret = cpu_lduw_kernel_secondary(env, addr); - break; - case 4: - ret = cpu_ldl_kernel_secondary(env, addr); - break; - default: - case 8: - ret = cpu_ldq_kernel_secondary(env, addr); - break; - } - } else { - switch (size) { - case 1: - ret = cpu_ldub_kernel(env, addr); - break; - case 2: - ret = cpu_lduw_kernel(env, addr); - break; - case 4: - ret = cpu_ldl_kernel(env, addr); - break; - default: - case 8: - ret = cpu_ldq_kernel(env, addr); - break; - } - } - } - } else { - /* secondary space access has lowest asi bit equal to 1 */ - if (asi & 1) { - switch (size) { - case 1: - ret = cpu_ldub_user_secondary(env, addr); - break; - case 2: - ret = cpu_lduw_user_secondary(env, addr); - break; - case 4: - ret = cpu_ldl_user_secondary(env, addr); - break; - default: - case 8: - ret = cpu_ldq_user_secondary(env, addr); - break; - } - } else { - switch (size) { - case 1: - ret = cpu_ldub_user(env, addr); - break; - case 2: - ret = cpu_lduw_user(env, addr); - break; - case 4: - ret = cpu_ldl_user(env, addr); - break; - default: - case 8: - ret = cpu_ldq_user(env, addr); - break; - } - } - } - break; - case 0x14: /* Bypass */ - case 0x15: /* Bypass, non-cacheable */ - case 0x1c: /* Bypass LE */ - case 0x1d: /* Bypass, non-cacheable LE */ - { - switch (size) { - case 1: - ret = ldub_phys(cs->as, addr); - break; - case 2: - ret = lduw_phys(cs->as, addr); - break; - case 4: - ret = ldl_phys(cs->as, addr); - break; - default: - case 8: - ret = ldq_phys(cs->as, addr); - break; - } - break; - } - case 0x24: /* Nucleus quad LDD 128 bit atomic */ - case 0x2c: /* Nucleus quad LDD 128 bit atomic LE - Only ldda allowed */ - helper_raise_exception(env, TT_ILL_INSN); - return 0; - case 0x04: /* Nucleus */ - case 0x0c: /* Nucleus Little Endian (LE) */ - { - switch (size) { - case 1: - ret = cpu_ldub_nucleus(env, addr); - break; - case 2: - ret = cpu_lduw_nucleus(env, addr); - break; - case 4: - ret = cpu_ldl_nucleus(env, addr); - break; - default: - case 8: - ret = cpu_ldq_nucleus(env, addr); - break; - } - break; - } - case 0x4a: /* UPA config */ - /* XXX */ - break; - case 0x45: /* LSU */ - ret = env->lsu; - break; - case 0x50: /* I-MMU regs */ - { - int reg = (addr >> 3) & 0xf; - - if (reg == 0) { - /* I-TSB Tag Target register */ - ret = ultrasparc_tag_target(env->immu.tag_access); - } else { - ret = env->immuregs[reg]; - } - - break; - } - case 0x51: /* I-MMU 8k TSB pointer */ - { - /* env->immuregs[5] holds I-MMU TSB register value - env->immuregs[6] holds I-MMU Tag Access register value */ - ret = ultrasparc_tsb_pointer(env->immu.tsb, env->immu.tag_access, - 8*1024); - break; - } - case 0x52: /* I-MMU 64k TSB pointer */ - { - /* env->immuregs[5] holds I-MMU TSB register value - env->immuregs[6] holds I-MMU Tag Access register value */ - ret = ultrasparc_tsb_pointer(env->immu.tsb, env->immu.tag_access, - 64*1024); - break; - } - case 0x55: /* I-MMU data access */ - { - int reg = (addr >> 3) & 0x3f; - - ret = env->itlb[reg].tte; - break; - } - case 0x56: /* I-MMU tag read */ - { - int reg = (addr >> 3) & 0x3f; - - ret = env->itlb[reg].tag; - break; - } - case 0x58: /* D-MMU regs */ - { - int reg = (addr >> 3) & 0xf; - - if (reg == 0) { - /* D-TSB Tag Target register */ - ret = ultrasparc_tag_target(env->dmmu.tag_access); - } else { - ret = env->dmmuregs[reg]; - } - break; - } - case 0x59: /* D-MMU 8k TSB pointer */ - { - /* env->dmmuregs[5] holds D-MMU TSB register value - env->dmmuregs[6] holds D-MMU Tag Access register value */ - ret = ultrasparc_tsb_pointer(env->dmmu.tsb, env->dmmu.tag_access, - 8*1024); - break; - } - case 0x5a: /* D-MMU 64k TSB pointer */ - { - /* env->dmmuregs[5] holds D-MMU TSB register value - env->dmmuregs[6] holds D-MMU Tag Access register value */ - ret = ultrasparc_tsb_pointer(env->dmmu.tsb, env->dmmu.tag_access, - 64*1024); - break; - } - case 0x5d: /* D-MMU data access */ - { - int reg = (addr >> 3) & 0x3f; - - ret = env->dtlb[reg].tte; - break; - } - case 0x5e: /* D-MMU tag read */ - { - int reg = (addr >> 3) & 0x3f; - - ret = env->dtlb[reg].tag; - break; - } - case 0x48: /* Interrupt dispatch, RO */ - break; - case 0x49: /* Interrupt data receive */ - ret = env->ivec_status; - break; - case 0x7f: /* Incoming interrupt vector, RO */ - { - int reg = (addr >> 4) & 0x3; - if (reg < 3) { - ret = env->ivec_data[reg]; - } - break; - } - case 0x46: /* D-cache data */ - case 0x47: /* D-cache tag access */ - case 0x4b: /* E-cache error enable */ - case 0x4c: /* E-cache asynchronous fault status */ - case 0x4d: /* E-cache asynchronous fault address */ - case 0x4e: /* E-cache tag data */ - case 0x66: /* I-cache instruction access */ - case 0x67: /* I-cache tag access */ - case 0x6e: /* I-cache predecode */ - case 0x6f: /* I-cache LRU etc. */ - case 0x76: /* E-cache tag */ - case 0x7e: /* E-cache tag */ - break; - case 0x5b: /* D-MMU data pointer */ - case 0x54: /* I-MMU data in, WO */ - case 0x57: /* I-MMU demap, WO */ - case 0x5c: /* D-MMU data in, WO */ - case 0x5f: /* D-MMU demap, WO */ - case 0x77: /* Interrupt vector, WO */ - default: - cpu_unassigned_access(cs, addr, false, false, 1, size); - ret = 0; - break; - } - - /* Convert from little endian */ - switch (asi) { - case 0x0c: /* Nucleus Little Endian (LE) */ - case 0x18: /* As if user primary LE */ - case 0x19: /* As if user secondary LE */ - case 0x1c: /* Bypass LE */ - case 0x1d: /* Bypass, non-cacheable LE */ - case 0x88: /* Primary LE */ - case 0x89: /* Secondary LE */ - switch(size) { - case 2: - ret = bswap16(ret); - break; - case 4: - ret = bswap32(ret); - break; - case 8: - ret = bswap64(ret); - break; - default: - break; - } - default: - break; - } - - /* Convert to signed number */ - if (sign) { - switch (size) { - case 1: - ret = (int8_t) ret; - break; - case 2: - ret = (int16_t) ret; - break; - case 4: - ret = (int32_t) ret; - break; - default: - break; - } - } -#ifdef DEBUG_ASI - dump_asi("read ", last_addr, asi, size, ret); -#endif - return ret; -} - -void helper_st_asi(CPUSPARCState *env, target_ulong addr, target_ulong val, - int asi, int size) -{ - SPARCCPU *cpu = sparc_env_get_cpu(env); - CPUState *cs = CPU(cpu); - -#ifdef DEBUG_ASI - dump_asi("write", addr, asi, size, val); -#endif - - asi &= 0xff; - - if ((asi < 0x80 && (env->pstate & PS_PRIV) == 0) - || (cpu_has_hypervisor(env) - && asi >= 0x30 && asi < 0x80 - && !(env->hpstate & HS_PRIV))) { - helper_raise_exception(env, TT_PRIV_ACT); - } - - helper_check_align(env, addr, size - 1); - addr = asi_address_mask(env, asi, addr); - - /* Convert to little endian */ - switch (asi) { - case 0x0c: /* Nucleus Little Endian (LE) */ - case 0x18: /* As if user primary LE */ - case 0x19: /* As if user secondary LE */ - case 0x1c: /* Bypass LE */ - case 0x1d: /* Bypass, non-cacheable LE */ - case 0x88: /* Primary LE */ - case 0x89: /* Secondary LE */ - switch (size) { - case 2: - val = bswap16(val); - break; - case 4: - val = bswap32(val); - break; - case 8: - val = bswap64(val); - break; - default: - break; - } - default: - break; - } - - switch (asi) { - case 0x10: /* As if user primary */ - case 0x11: /* As if user secondary */ - case 0x18: /* As if user primary LE */ - case 0x19: /* As if user secondary LE */ - case 0x80: /* Primary */ - case 0x81: /* Secondary */ - case 0x88: /* Primary LE */ - case 0x89: /* Secondary LE */ - case 0xe2: /* UA2007 Primary block init */ - case 0xe3: /* UA2007 Secondary block init */ - if ((asi & 0x80) && (env->pstate & PS_PRIV)) { - if (cpu_hypervisor_mode(env)) { - switch (size) { - case 1: - cpu_stb_hypv(env, addr, val); - break; - case 2: - cpu_stw_hypv(env, addr, val); - break; - case 4: - cpu_stl_hypv(env, addr, val); - break; - case 8: - default: - cpu_stq_hypv(env, addr, val); - break; - } - } else { - /* secondary space access has lowest asi bit equal to 1 */ - if (asi & 1) { - switch (size) { - case 1: - cpu_stb_kernel_secondary(env, addr, val); - break; - case 2: - cpu_stw_kernel_secondary(env, addr, val); - break; - case 4: - cpu_stl_kernel_secondary(env, addr, val); - break; - case 8: - default: - cpu_stq_kernel_secondary(env, addr, val); - break; - } - } else { - switch (size) { - case 1: - cpu_stb_kernel(env, addr, val); - break; - case 2: - cpu_stw_kernel(env, addr, val); - break; - case 4: - cpu_stl_kernel(env, addr, val); - break; - case 8: - default: - cpu_stq_kernel(env, addr, val); - break; - } - } - } - } else { - /* secondary space access has lowest asi bit equal to 1 */ - if (asi & 1) { - switch (size) { - case 1: - cpu_stb_user_secondary(env, addr, val); - break; - case 2: - cpu_stw_user_secondary(env, addr, val); - break; - case 4: - cpu_stl_user_secondary(env, addr, val); - break; - case 8: - default: - cpu_stq_user_secondary(env, addr, val); - break; - } - } else { - switch (size) { - case 1: - cpu_stb_user(env, addr, val); - break; - case 2: - cpu_stw_user(env, addr, val); - break; - case 4: - cpu_stl_user(env, addr, val); - break; - case 8: - default: - cpu_stq_user(env, addr, val); - break; - } - } - } - break; - case 0x14: /* Bypass */ - case 0x15: /* Bypass, non-cacheable */ - case 0x1c: /* Bypass LE */ - case 0x1d: /* Bypass, non-cacheable LE */ - { - switch (size) { - case 1: - stb_phys(cs->as, addr, val); - break; - case 2: - stw_phys(cs->as, addr, val); - break; - case 4: - stl_phys(cs->as, addr, val); - break; - case 8: - default: - stq_phys(cs->as, addr, val); - break; - } - } - return; - case 0x24: /* Nucleus quad LDD 128 bit atomic */ - case 0x2c: /* Nucleus quad LDD 128 bit atomic LE - Only ldda allowed */ - helper_raise_exception(env, TT_ILL_INSN); - return; - case 0x04: /* Nucleus */ - case 0x0c: /* Nucleus Little Endian (LE) */ - { - switch (size) { - case 1: - cpu_stb_nucleus(env, addr, val); - break; - case 2: - cpu_stw_nucleus(env, addr, val); - break; - case 4: - cpu_stl_nucleus(env, addr, val); - break; - default: - case 8: - cpu_stq_nucleus(env, addr, val); - break; - } - break; - } - - case 0x4a: /* UPA config */ - /* XXX */ - return; - case 0x45: /* LSU */ - { - uint64_t oldreg; - - oldreg = env->lsu; - env->lsu = val & (DMMU_E | IMMU_E); - /* Mappings generated during D/I MMU disabled mode are - invalid in normal mode */ - if (oldreg != env->lsu) { - DPRINTF_MMU("LSU change: 0x%" PRIx64 " -> 0x%" PRIx64 "\n", - oldreg, env->lsu); -#ifdef DEBUG_MMU - dump_mmu(stdout, fprintf, env); -#endif - tlb_flush(CPU(cpu), 1); - } - return; - } - case 0x50: /* I-MMU regs */ - { - int reg = (addr >> 3) & 0xf; - uint64_t oldreg; - - oldreg = env->immuregs[reg]; - switch (reg) { - case 0: /* RO */ - return; - case 1: /* Not in I-MMU */ - case 2: - return; - case 3: /* SFSR */ - if ((val & 1) == 0) { - val = 0; /* Clear SFSR */ - } - env->immu.sfsr = val; - break; - case 4: /* RO */ - return; - case 5: /* TSB access */ - DPRINTF_MMU("immu TSB write: 0x%016" PRIx64 " -> 0x%016" - PRIx64 "\n", env->immu.tsb, val); - env->immu.tsb = val; - break; - case 6: /* Tag access */ - env->immu.tag_access = val; - break; - case 7: - case 8: - return; - default: - break; - } - - if (oldreg != env->immuregs[reg]) { - DPRINTF_MMU("immu change reg[%d]: 0x%016" PRIx64 " -> 0x%016" - PRIx64 "\n", reg, oldreg, env->immuregs[reg]); - } -#ifdef DEBUG_MMU - dump_mmu(stdout, fprintf, env); -#endif - return; - } - case 0x54: /* I-MMU data in */ - replace_tlb_1bit_lru(env->itlb, env->immu.tag_access, val, "immu", env); - return; - case 0x55: /* I-MMU data access */ - { - /* TODO: auto demap */ - - unsigned int i = (addr >> 3) & 0x3f; - - replace_tlb_entry(&env->itlb[i], env->immu.tag_access, val, env); - -#ifdef DEBUG_MMU - DPRINTF_MMU("immu data access replaced entry [%i]\n", i); - dump_mmu(stdout, fprintf, env); -#endif - return; - } - case 0x57: /* I-MMU demap */ - demap_tlb(env->itlb, addr, "immu", env); - return; - case 0x58: /* D-MMU regs */ - { - int reg = (addr >> 3) & 0xf; - uint64_t oldreg; - - oldreg = env->dmmuregs[reg]; - switch (reg) { - case 0: /* RO */ - case 4: - return; - case 3: /* SFSR */ - if ((val & 1) == 0) { - val = 0; /* Clear SFSR, Fault address */ - env->dmmu.sfar = 0; - } - env->dmmu.sfsr = val; - break; - case 1: /* Primary context */ - env->dmmu.mmu_primary_context = val; - /* can be optimized to only flush MMU_USER_IDX - and MMU_KERNEL_IDX entries */ - tlb_flush(CPU(cpu), 1); - break; - case 2: /* Secondary context */ - env->dmmu.mmu_secondary_context = val; - /* can be optimized to only flush MMU_USER_SECONDARY_IDX - and MMU_KERNEL_SECONDARY_IDX entries */ - tlb_flush(CPU(cpu), 1); - break; - case 5: /* TSB access */ - DPRINTF_MMU("dmmu TSB write: 0x%016" PRIx64 " -> 0x%016" - PRIx64 "\n", env->dmmu.tsb, val); - env->dmmu.tsb = val; - break; - case 6: /* Tag access */ - env->dmmu.tag_access = val; - break; - case 7: /* Virtual Watchpoint */ - case 8: /* Physical Watchpoint */ - default: - env->dmmuregs[reg] = val; - break; - } - - if (oldreg != env->dmmuregs[reg]) { - DPRINTF_MMU("dmmu change reg[%d]: 0x%016" PRIx64 " -> 0x%016" - PRIx64 "\n", reg, oldreg, env->dmmuregs[reg]); - } -#ifdef DEBUG_MMU - dump_mmu(stdout, fprintf, env); -#endif - return; - } - case 0x5c: /* D-MMU data in */ - replace_tlb_1bit_lru(env->dtlb, env->dmmu.tag_access, val, "dmmu", env); - return; - case 0x5d: /* D-MMU data access */ - { - unsigned int i = (addr >> 3) & 0x3f; - - replace_tlb_entry(&env->dtlb[i], env->dmmu.tag_access, val, env); - -#ifdef DEBUG_MMU - DPRINTF_MMU("dmmu data access replaced entry [%i]\n", i); - dump_mmu(stdout, fprintf, env); -#endif - return; - } - case 0x5f: /* D-MMU demap */ - demap_tlb(env->dtlb, addr, "dmmu", env); - return; - case 0x49: /* Interrupt data receive */ - env->ivec_status = val & 0x20; - return; - case 0x46: /* D-cache data */ - case 0x47: /* D-cache tag access */ - case 0x4b: /* E-cache error enable */ - case 0x4c: /* E-cache asynchronous fault status */ - case 0x4d: /* E-cache asynchronous fault address */ - case 0x4e: /* E-cache tag data */ - case 0x66: /* I-cache instruction access */ - case 0x67: /* I-cache tag access */ - case 0x6e: /* I-cache predecode */ - case 0x6f: /* I-cache LRU etc. */ - case 0x76: /* E-cache tag */ - case 0x7e: /* E-cache tag */ - return; - case 0x51: /* I-MMU 8k TSB pointer, RO */ - case 0x52: /* I-MMU 64k TSB pointer, RO */ - case 0x56: /* I-MMU tag read, RO */ - case 0x59: /* D-MMU 8k TSB pointer, RO */ - case 0x5a: /* D-MMU 64k TSB pointer, RO */ - case 0x5b: /* D-MMU data pointer, RO */ - case 0x5e: /* D-MMU tag read, RO */ - case 0x48: /* Interrupt dispatch, RO */ - case 0x7f: /* Incoming interrupt vector, RO */ - case 0x82: /* Primary no-fault, RO */ - case 0x83: /* Secondary no-fault, RO */ - case 0x8a: /* Primary no-fault LE, RO */ - case 0x8b: /* Secondary no-fault LE, RO */ - default: - cpu_unassigned_access(cs, addr, true, false, 1, size); - return; - } -} -#endif /* CONFIG_USER_ONLY */ - -void helper_ldda_asi(CPUSPARCState *env, target_ulong addr, int asi, int rd) -{ - if ((asi < 0x80 && (env->pstate & PS_PRIV) == 0) - || (cpu_has_hypervisor(env) - && asi >= 0x30 && asi < 0x80 - && !(env->hpstate & HS_PRIV))) { - helper_raise_exception(env, TT_PRIV_ACT); - } - - addr = asi_address_mask(env, asi, addr); - - switch (asi) { -#if !defined(CONFIG_USER_ONLY) - case 0x24: /* Nucleus quad LDD 128 bit atomic */ - case 0x2c: /* Nucleus quad LDD 128 bit atomic LE */ - helper_check_align(env, addr, 0xf); - if (rd == 0) { - env->gregs[1] = cpu_ldq_nucleus(env, addr + 8); - if (asi == 0x2c) { - bswap64s(&env->gregs[1]); - } - } else if (rd < 8) { - env->gregs[rd] = cpu_ldq_nucleus(env, addr); - env->gregs[rd + 1] = cpu_ldq_nucleus(env, addr + 8); - if (asi == 0x2c) { - bswap64s(&env->gregs[rd]); - bswap64s(&env->gregs[rd + 1]); - } - } else { - env->regwptr[rd - 8] = cpu_ldq_nucleus(env, addr); - env->regwptr[rd + 1 - 8] = cpu_ldq_nucleus(env, addr + 8); - if (asi == 0x2c) { - bswap64s(&env->regwptr[rd - 8]); - bswap64s(&env->regwptr[rd + 1 - 8]); - } - } - break; -#endif - default: - helper_check_align(env, addr, 0x3); - if (rd == 0) { - env->gregs[1] = helper_ld_asi(env, addr + 4, asi, 4, 0); - } else if (rd < 8) { - env->gregs[rd] = helper_ld_asi(env, addr, asi, 4, 0); - env->gregs[rd + 1] = helper_ld_asi(env, addr + 4, asi, 4, 0); - } else { - env->regwptr[rd - 8] = helper_ld_asi(env, addr, asi, 4, 0); - env->regwptr[rd + 1 - 8] = helper_ld_asi(env, addr + 4, asi, 4, 0); - } - break; - } -} - -void helper_ldf_asi(CPUSPARCState *env, target_ulong addr, int asi, int size, - int rd) -{ - unsigned int i; - target_ulong val; - - helper_check_align(env, addr, 3); - addr = asi_address_mask(env, asi, addr); - - switch (asi) { - case 0xf0: /* UA2007/JPS1 Block load primary */ - case 0xf1: /* UA2007/JPS1 Block load secondary */ - case 0xf8: /* UA2007/JPS1 Block load primary LE */ - case 0xf9: /* UA2007/JPS1 Block load secondary LE */ - if (rd & 7) { - helper_raise_exception(env, TT_ILL_INSN); - return; - } - helper_check_align(env, addr, 0x3f); - for (i = 0; i < 8; i++, rd += 2, addr += 8) { - env->fpr[rd / 2].ll = helper_ld_asi(env, addr, asi & 0x8f, 8, 0); - } - return; - - case 0x16: /* UA2007 Block load primary, user privilege */ - case 0x17: /* UA2007 Block load secondary, user privilege */ - case 0x1e: /* UA2007 Block load primary LE, user privilege */ - case 0x1f: /* UA2007 Block load secondary LE, user privilege */ - case 0x70: /* JPS1 Block load primary, user privilege */ - case 0x71: /* JPS1 Block load secondary, user privilege */ - case 0x78: /* JPS1 Block load primary LE, user privilege */ - case 0x79: /* JPS1 Block load secondary LE, user privilege */ - if (rd & 7) { - helper_raise_exception(env, TT_ILL_INSN); - return; - } - helper_check_align(env, addr, 0x3f); - for (i = 0; i < 8; i++, rd += 2, addr += 8) { - env->fpr[rd / 2].ll = helper_ld_asi(env, addr, asi & 0x19, 8, 0); - } - return; - - default: - break; - } - - switch (size) { - default: - case 4: - val = helper_ld_asi(env, addr, asi, size, 0); - if (rd & 1) { - env->fpr[rd / 2].l.lower = val; - } else { - env->fpr[rd / 2].l.upper = val; - } - break; - case 8: - env->fpr[rd / 2].ll = helper_ld_asi(env, addr, asi, size, 0); - break; - case 16: - env->fpr[rd / 2].ll = helper_ld_asi(env, addr, asi, 8, 0); - env->fpr[rd / 2 + 1].ll = helper_ld_asi(env, addr + 8, asi, 8, 0); - break; - } -} - -void helper_stf_asi(CPUSPARCState *env, target_ulong addr, int asi, int size, - int rd) -{ - unsigned int i; - target_ulong val; - - addr = asi_address_mask(env, asi, addr); - - switch (asi) { - case 0xe0: /* UA2007/JPS1 Block commit store primary (cache flush) */ - case 0xe1: /* UA2007/JPS1 Block commit store secondary (cache flush) */ - case 0xf0: /* UA2007/JPS1 Block store primary */ - case 0xf1: /* UA2007/JPS1 Block store secondary */ - case 0xf8: /* UA2007/JPS1 Block store primary LE */ - case 0xf9: /* UA2007/JPS1 Block store secondary LE */ - if (rd & 7) { - helper_raise_exception(env, TT_ILL_INSN); - return; - } - helper_check_align(env, addr, 0x3f); - for (i = 0; i < 8; i++, rd += 2, addr += 8) { - helper_st_asi(env, addr, env->fpr[rd / 2].ll, asi & 0x8f, 8); - } - - return; - case 0x16: /* UA2007 Block load primary, user privilege */ - case 0x17: /* UA2007 Block load secondary, user privilege */ - case 0x1e: /* UA2007 Block load primary LE, user privilege */ - case 0x1f: /* UA2007 Block load secondary LE, user privilege */ - case 0x70: /* JPS1 Block store primary, user privilege */ - case 0x71: /* JPS1 Block store secondary, user privilege */ - case 0x78: /* JPS1 Block load primary LE, user privilege */ - case 0x79: /* JPS1 Block load secondary LE, user privilege */ - if (rd & 7) { - helper_raise_exception(env, TT_ILL_INSN); - return; - } - helper_check_align(env, addr, 0x3f); - for (i = 0; i < 8; i++, rd += 2, addr += 8) { - helper_st_asi(env, addr, env->fpr[rd / 2].ll, asi & 0x19, 8); - } - - return; - case 0xd2: /* 16-bit floating point load primary */ - case 0xd3: /* 16-bit floating point load secondary */ - case 0xda: /* 16-bit floating point load primary, LE */ - case 0xdb: /* 16-bit floating point load secondary, LE */ - helper_check_align(env, addr, 1); - /* Fall through */ - case 0xd0: /* 8-bit floating point load primary */ - case 0xd1: /* 8-bit floating point load secondary */ - case 0xd8: /* 8-bit floating point load primary, LE */ - case 0xd9: /* 8-bit floating point load secondary, LE */ - val = env->fpr[rd / 2].l.lower; - helper_st_asi(env, addr, val, asi & 0x8d, ((asi & 2) >> 1) + 1); - return; - default: - helper_check_align(env, addr, 3); - break; - } - - switch (size) { - default: - case 4: - if (rd & 1) { - val = env->fpr[rd / 2].l.lower; - } else { - val = env->fpr[rd / 2].l.upper; - } - helper_st_asi(env, addr, val, asi, size); - break; - case 8: - helper_st_asi(env, addr, env->fpr[rd / 2].ll, asi, size); - break; - case 16: - helper_st_asi(env, addr, env->fpr[rd / 2].ll, asi, 8); - helper_st_asi(env, addr + 8, env->fpr[rd / 2 + 1].ll, asi, 8); - break; - } -} - -target_ulong helper_casx_asi(CPUSPARCState *env, target_ulong addr, - target_ulong val1, target_ulong val2, - uint32_t asi) -{ - target_ulong ret; - - ret = helper_ld_asi(env, addr, asi, 8, 0); - if (val2 == ret) { - helper_st_asi(env, addr, val1, asi, 8); - } - return ret; -} -#endif /* TARGET_SPARC64 */ - -#if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64) -target_ulong helper_cas_asi(CPUSPARCState *env, target_ulong addr, - target_ulong val1, target_ulong val2, uint32_t asi) -{ - target_ulong ret; - - val2 &= 0xffffffffUL; - ret = helper_ld_asi(env, addr, asi, 4, 0); - ret &= 0xffffffffUL; - if (val2 == ret) { - helper_st_asi(env, addr, val1 & 0xffffffffUL, asi, 4); - } - return ret; -} -#endif /* !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64) */ - -void helper_ldqf(CPUSPARCState *env, target_ulong addr, int mem_idx) -{ - /* XXX add 128 bit load */ - CPU_QuadU u; - - helper_check_align(env, addr, 7); -#if !defined(CONFIG_USER_ONLY) - switch (mem_idx) { - case MMU_USER_IDX: - u.ll.upper = cpu_ldq_user(env, addr); - u.ll.lower = cpu_ldq_user(env, addr + 8); - QT0 = u.q; - break; - case MMU_KERNEL_IDX: - u.ll.upper = cpu_ldq_kernel(env, addr); - u.ll.lower = cpu_ldq_kernel(env, addr + 8); - QT0 = u.q; - break; -#ifdef TARGET_SPARC64 - case MMU_HYPV_IDX: - u.ll.upper = cpu_ldq_hypv(env, addr); - u.ll.lower = cpu_ldq_hypv(env, addr + 8); - QT0 = u.q; - break; -#endif - default: - DPRINTF_MMU("helper_ldqf: need to check MMU idx %d\n", mem_idx); - break; - } -#else - u.ll.upper = cpu_ldq_data(env, address_mask(env, addr)); - u.ll.lower = cpu_ldq_data(env, address_mask(env, addr + 8)); - QT0 = u.q; -#endif -} - -void helper_stqf(CPUSPARCState *env, target_ulong addr, int mem_idx) -{ - /* XXX add 128 bit store */ - CPU_QuadU u; - - helper_check_align(env, addr, 7); -#if !defined(CONFIG_USER_ONLY) - switch (mem_idx) { - case MMU_USER_IDX: - u.q = QT0; - cpu_stq_user(env, addr, u.ll.upper); - cpu_stq_user(env, addr + 8, u.ll.lower); - break; - case MMU_KERNEL_IDX: - u.q = QT0; - cpu_stq_kernel(env, addr, u.ll.upper); - cpu_stq_kernel(env, addr + 8, u.ll.lower); - break; -#ifdef TARGET_SPARC64 - case MMU_HYPV_IDX: - u.q = QT0; - cpu_stq_hypv(env, addr, u.ll.upper); - cpu_stq_hypv(env, addr + 8, u.ll.lower); - break; -#endif - default: - DPRINTF_MMU("helper_stqf: need to check MMU idx %d\n", mem_idx); - break; - } -#else - u.q = QT0; - cpu_stq_data(env, address_mask(env, addr), u.ll.upper); - cpu_stq_data(env, address_mask(env, addr + 8), u.ll.lower); -#endif -} - -#if !defined(CONFIG_USER_ONLY) -#ifndef TARGET_SPARC64 -void sparc_cpu_unassigned_access(CPUState *cs, hwaddr addr, - bool is_write, bool is_exec, int is_asi, - unsigned size) -{ - SPARCCPU *cpu = SPARC_CPU(cs); - CPUSPARCState *env = &cpu->env; - int fault_type; - -#ifdef DEBUG_UNASSIGNED - if (is_asi) { - printf("Unassigned mem %s access of %d byte%s to " TARGET_FMT_plx - " asi 0x%02x from " TARGET_FMT_lx "\n", - is_exec ? "exec" : is_write ? "write" : "read", size, - size == 1 ? "" : "s", addr, is_asi, env->pc); - } else { - printf("Unassigned mem %s access of %d byte%s to " TARGET_FMT_plx - " from " TARGET_FMT_lx "\n", - is_exec ? "exec" : is_write ? "write" : "read", size, - size == 1 ? "" : "s", addr, env->pc); - } -#endif - /* Don't overwrite translation and access faults */ - fault_type = (env->mmuregs[3] & 0x1c) >> 2; - if ((fault_type > 4) || (fault_type == 0)) { - env->mmuregs[3] = 0; /* Fault status register */ - if (is_asi) { - env->mmuregs[3] |= 1 << 16; - } - if (env->psrs) { - env->mmuregs[3] |= 1 << 5; - } - if (is_exec) { - env->mmuregs[3] |= 1 << 6; - } - if (is_write) { - env->mmuregs[3] |= 1 << 7; - } - env->mmuregs[3] |= (5 << 2) | 2; - /* SuperSPARC will never place instruction fault addresses in the FAR */ - if (!is_exec) { - env->mmuregs[4] = addr; /* Fault address register */ - } - } - /* overflow (same type fault was not read before another fault) */ - if (fault_type == ((env->mmuregs[3] & 0x1c)) >> 2) { - env->mmuregs[3] |= 1; - } - - if ((env->mmuregs[0] & MMU_E) && !(env->mmuregs[0] & MMU_NF)) { - if (is_exec) { - helper_raise_exception(env, TT_CODE_ACCESS); - } else { - helper_raise_exception(env, TT_DATA_ACCESS); - } - } - - /* flush neverland mappings created during no-fault mode, - so the sequential MMU faults report proper fault types */ - if (env->mmuregs[0] & MMU_NF) { - tlb_flush(cs, 1); - } -} -#else -void sparc_cpu_unassigned_access(CPUState *cs, hwaddr addr, - bool is_write, bool is_exec, int is_asi, - unsigned size) -{ - SPARCCPU *cpu = SPARC_CPU(cs); - CPUSPARCState *env = &cpu->env; - -#ifdef DEBUG_UNASSIGNED - printf("Unassigned mem access to " TARGET_FMT_plx " from " TARGET_FMT_lx - "\n", addr, env->pc); -#endif - - if (is_exec) { - helper_raise_exception(env, TT_CODE_ACCESS); - } else { - helper_raise_exception(env, TT_DATA_ACCESS); - } -} -#endif -#endif - -#if !defined(CONFIG_USER_ONLY) -void QEMU_NORETURN sparc_cpu_do_unaligned_access(CPUState *cs, - vaddr addr, int is_write, - int is_user, uintptr_t retaddr) -{ - SPARCCPU *cpu = SPARC_CPU(cs); - CPUSPARCState *env = &cpu->env; - -#ifdef DEBUG_UNALIGNED - printf("Unaligned access to 0x" TARGET_FMT_lx " from 0x" TARGET_FMT_lx - "\n", addr, env->pc); -#endif - if (retaddr) { - cpu_restore_state(CPU(cpu), retaddr); - } - helper_raise_exception(env, TT_UNALIGNED); -} - -/* try to fill the TLB and return an exception if error. If retaddr is - NULL, it means that the function was called in C code (i.e. not - from generated code or from helper.c) */ -/* XXX: fix it to restore all registers */ -void tlb_fill(CPUState *cs, target_ulong addr, int is_write, int mmu_idx, - uintptr_t retaddr) -{ - int ret; - - ret = sparc_cpu_handle_mmu_fault(cs, addr, is_write, mmu_idx); - if (ret) { - if (retaddr) { - cpu_restore_state(cs, retaddr); - } - cpu_loop_exit(cs); - } -} -#endif diff --git a/qemu/target-sparc/machine.c b/qemu/target-sparc/machine.c deleted file mode 100644 index 1046016f3..000000000 --- a/qemu/target-sparc/machine.c +++ /dev/null @@ -1,191 +0,0 @@ -#include "qemu/osdep.h" -#include "hw/hw.h" -#include "hw/boards.h" -#include "qemu/timer.h" - -#include "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() - }, -}; diff --git a/qemu/target-sparc/mmu_helper.c b/qemu/target-sparc/mmu_helper.c deleted file mode 100644 index aa80c4829..000000000 --- a/qemu/target-sparc/mmu_helper.c +++ /dev/null @@ -1,868 +0,0 @@ -/* - * 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 "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 ((env->mmuregs[0] & MMU_E) == 0) { /* MMU disabled */ - *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; - - int is_user = (mmu_idx == MMU_USER_IDX || - mmu_idx == MMU_USER_SECONDARY_IDX); - - if ((env->lsu & DMMU_E) == 0) { /* DMMU disabled */ - *physical = ultrasparc_truncate_physical(address); - *prot = PAGE_READ | PAGE_WRITE; - return 0; - } - - switch (mmu_idx) { - case MMU_USER_IDX: - case MMU_KERNEL_IDX: - context = env->dmmu.mmu_primary_context & 0x1fff; - sfsr |= SFSR_CT_PRIMARY; - break; - case MMU_USER_SECONDARY_IDX: - 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; - - int is_user = (mmu_idx == MMU_USER_IDX || - mmu_idx == MMU_USER_SECONDARY_IDX); - - if ((env->lsu & IMMU_E) == 0 || (env->pstate & PS_RED) != 0) { - /* IMMU disabled */ - *physical = ultrasparc_truncate_physical(address); - *prot = PAGE_EXEC; - return 0; - } - - 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 (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 diff --git a/qemu/target-sparc/monitor.c b/qemu/target-sparc/monitor.c deleted file mode 100644 index 7cc1b0f87..000000000 --- a/qemu/target-sparc/monitor.c +++ /dev/null @@ -1,159 +0,0 @@ -/* - * 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; -} diff --git a/qemu/target-sparc/translate.c b/qemu/target-sparc/translate.c deleted file mode 100644 index 7998ff57b..000000000 --- a/qemu/target-sparc/translate.c +++ /dev/null @@ -1,5447 +0,0 @@ -/* - SPARC translation - - Copyright (C) 2003 Thomas M. Ogrisegg <tom@fnord.at> - 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 "disas/disas.h" -#include "exec/helper-proto.h" -#include "tcg-op.h" -#include "exec/cpu_ldst.h" - -#include "exec/helper-gen.h" - -#include "trace-tcg.h" -#include "exec/log.h" - - -#define DEBUG_DISAS - -#define DYNAMIC_PC 1 /* dynamic pc value */ -#define JUMP_PC 2 /* dynamic pc value which takes only two values - according to jump_pc[T2] */ - -/* global register indexes */ -static TCGv_env cpu_env; -static TCGv_ptr cpu_regwptr; -static TCGv cpu_cc_src, cpu_cc_src2, cpu_cc_dst; -static TCGv_i32 cpu_cc_op; -static TCGv_i32 cpu_psr; -static TCGv cpu_fsr, cpu_pc, cpu_npc; -static TCGv cpu_regs[32]; -static TCGv cpu_y; -#ifndef CONFIG_USER_ONLY -static TCGv cpu_tbr; -#endif -static TCGv cpu_cond; -#ifdef TARGET_SPARC64 -static TCGv_i32 cpu_xcc, cpu_asi, cpu_fprs; -static TCGv cpu_gsr; -static TCGv cpu_tick_cmpr, cpu_stick_cmpr, cpu_hstick_cmpr; -static TCGv cpu_hintp, cpu_htba, cpu_hver, cpu_ssr, cpu_ver; -static TCGv_i32 cpu_softint; -#else -static TCGv cpu_wim; -#endif -/* Floating point registers */ -static TCGv_i64 cpu_fpr[TARGET_DPREGS]; - -#include "exec/gen-icount.h" - -typedef struct DisasContext { - target_ulong pc; /* current Program Counter: integer or DYNAMIC_PC */ - target_ulong npc; /* next PC: integer or DYNAMIC_PC or JUMP_PC */ - target_ulong jump_pc[2]; /* used when JUMP_PC pc value is used */ - int is_br; - int mem_idx; - int fpu_enabled; - int address_mask_32bit; - int singlestep; - uint32_t cc_op; /* current CC operation */ - struct TranslationBlock *tb; - sparc_def_t *def; - TCGv_i32 t32[3]; - TCGv ttl[5]; - int n_t32; - int n_ttl; -} DisasContext; - -typedef struct { - TCGCond cond; - bool is_bool; - bool g1, g2; - TCGv c1, c2; -} DisasCompare; - -// This function uses non-native bit order -#define GET_FIELD(X, FROM, TO) \ - ((X) >> (31 - (TO)) & ((1 << ((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, 31 - (TO), 31 - (FROM)) - -#define GET_FIELDs(x,a,b) sign_extend (GET_FIELD(x,a,b), (b) - (a) + 1) -#define GET_FIELD_SPs(x,a,b) sign_extend (GET_FIELD_SP(x,a,b), ((b) - (a) + 1)) - -#ifdef TARGET_SPARC64 -#define DFPREG(r) (((r & 1) << 5) | (r & 0x1e)) -#define QFPREG(r) (((r & 1) << 5) | (r & 0x1c)) -#else -#define DFPREG(r) (r & 0x1e) -#define QFPREG(r) (r & 0x1c) -#endif - -#define UA2005_HTRAP_MASK 0xff -#define V8_TRAP_MASK 0x7f - -static int sign_extend(int x, int len) -{ - len = 32 - len; - return (x << len) >> len; -} - -#define IS_IMM (insn & (1<<13)) - -static inline TCGv_i32 get_temp_i32(DisasContext *dc) -{ - TCGv_i32 t; - assert(dc->n_t32 < ARRAY_SIZE(dc->t32)); - dc->t32[dc->n_t32++] = t = tcg_temp_new_i32(); - return t; -} - -static inline TCGv get_temp_tl(DisasContext *dc) -{ - TCGv t; - assert(dc->n_ttl < ARRAY_SIZE(dc->ttl)); - dc->ttl[dc->n_ttl++] = t = tcg_temp_new(); - return t; -} - -static inline void gen_update_fprs_dirty(int rd) -{ -#if defined(TARGET_SPARC64) - tcg_gen_ori_i32(cpu_fprs, cpu_fprs, (rd < 32) ? 1 : 2); -#endif -} - -/* floating point registers moves */ -static TCGv_i32 gen_load_fpr_F(DisasContext *dc, unsigned int src) -{ -#if TCG_TARGET_REG_BITS == 32 - if (src & 1) { - return TCGV_LOW(cpu_fpr[src / 2]); - } else { - return TCGV_HIGH(cpu_fpr[src / 2]); - } -#else - if (src & 1) { - return MAKE_TCGV_I32(GET_TCGV_I64(cpu_fpr[src / 2])); - } else { - TCGv_i32 ret = get_temp_i32(dc); - TCGv_i64 t = tcg_temp_new_i64(); - - tcg_gen_shri_i64(t, cpu_fpr[src / 2], 32); - tcg_gen_extrl_i64_i32(ret, t); - tcg_temp_free_i64(t); - - return ret; - } -#endif -} - -static void gen_store_fpr_F(DisasContext *dc, unsigned int dst, TCGv_i32 v) -{ -#if TCG_TARGET_REG_BITS == 32 - if (dst & 1) { - tcg_gen_mov_i32(TCGV_LOW(cpu_fpr[dst / 2]), v); - } else { - tcg_gen_mov_i32(TCGV_HIGH(cpu_fpr[dst / 2]), v); - } -#else - TCGv_i64 t = MAKE_TCGV_I64(GET_TCGV_I32(v)); - tcg_gen_deposit_i64(cpu_fpr[dst / 2], cpu_fpr[dst / 2], t, - (dst & 1 ? 0 : 32), 32); -#endif - gen_update_fprs_dirty(dst); -} - -static TCGv_i32 gen_dest_fpr_F(DisasContext *dc) -{ - return get_temp_i32(dc); -} - -static TCGv_i64 gen_load_fpr_D(DisasContext *dc, unsigned int src) -{ - src = DFPREG(src); - return cpu_fpr[src / 2]; -} - -static void gen_store_fpr_D(DisasContext *dc, unsigned int dst, TCGv_i64 v) -{ - dst = DFPREG(dst); - tcg_gen_mov_i64(cpu_fpr[dst / 2], v); - gen_update_fprs_dirty(dst); -} - -static TCGv_i64 gen_dest_fpr_D(DisasContext *dc, unsigned int dst) -{ - return cpu_fpr[DFPREG(dst) / 2]; -} - -static void gen_op_load_fpr_QT0(unsigned int src) -{ - tcg_gen_st_i64(cpu_fpr[src / 2], cpu_env, offsetof(CPUSPARCState, qt0) + - offsetof(CPU_QuadU, ll.upper)); - tcg_gen_st_i64(cpu_fpr[src/2 + 1], cpu_env, offsetof(CPUSPARCState, qt0) + - offsetof(CPU_QuadU, ll.lower)); -} - -static void gen_op_load_fpr_QT1(unsigned int src) -{ - tcg_gen_st_i64(cpu_fpr[src / 2], cpu_env, offsetof(CPUSPARCState, qt1) + - offsetof(CPU_QuadU, ll.upper)); - tcg_gen_st_i64(cpu_fpr[src/2 + 1], cpu_env, offsetof(CPUSPARCState, qt1) + - offsetof(CPU_QuadU, ll.lower)); -} - -static void gen_op_store_QT0_fpr(unsigned int dst) -{ - tcg_gen_ld_i64(cpu_fpr[dst / 2], cpu_env, offsetof(CPUSPARCState, qt0) + - offsetof(CPU_QuadU, ll.upper)); - tcg_gen_ld_i64(cpu_fpr[dst/2 + 1], cpu_env, offsetof(CPUSPARCState, qt0) + - offsetof(CPU_QuadU, ll.lower)); -} - -#ifdef TARGET_SPARC64 -static void gen_move_Q(unsigned int rd, unsigned int rs) -{ - rd = QFPREG(rd); - rs = QFPREG(rs); - - tcg_gen_mov_i64(cpu_fpr[rd / 2], cpu_fpr[rs / 2]); - tcg_gen_mov_i64(cpu_fpr[rd / 2 + 1], cpu_fpr[rs / 2 + 1]); - gen_update_fprs_dirty(rd); -} -#endif - -/* moves */ -#ifdef CONFIG_USER_ONLY -#define supervisor(dc) 0 -#ifdef TARGET_SPARC64 -#define hypervisor(dc) 0 -#endif -#else -#define supervisor(dc) (dc->mem_idx >= MMU_KERNEL_IDX) -#ifdef TARGET_SPARC64 -#define hypervisor(dc) (dc->mem_idx == MMU_HYPV_IDX) -#else -#endif -#endif - -#ifdef TARGET_SPARC64 -#ifndef TARGET_ABI32 -#define AM_CHECK(dc) ((dc)->address_mask_32bit) -#else -#define AM_CHECK(dc) (1) -#endif -#endif - -static inline void gen_address_mask(DisasContext *dc, TCGv addr) -{ -#ifdef TARGET_SPARC64 - if (AM_CHECK(dc)) - tcg_gen_andi_tl(addr, addr, 0xffffffffULL); -#endif -} - -static inline TCGv gen_load_gpr(DisasContext *dc, int reg) -{ - if (reg > 0) { - assert(reg < 32); - return cpu_regs[reg]; - } else { - TCGv t = get_temp_tl(dc); - tcg_gen_movi_tl(t, 0); - return t; - } -} - -static inline void gen_store_gpr(DisasContext *dc, int reg, TCGv v) -{ - if (reg > 0) { - assert(reg < 32); - tcg_gen_mov_tl(cpu_regs[reg], v); - } -} - -static inline TCGv gen_dest_gpr(DisasContext *dc, int reg) -{ - if (reg > 0) { - assert(reg < 32); - return cpu_regs[reg]; - } else { - return get_temp_tl(dc); - } -} - -static inline void gen_goto_tb(DisasContext *s, int tb_num, - target_ulong pc, target_ulong npc) -{ - TranslationBlock *tb; - - tb = s->tb; - if ((pc & TARGET_PAGE_MASK) == (tb->pc & TARGET_PAGE_MASK) && - (npc & TARGET_PAGE_MASK) == (tb->pc & TARGET_PAGE_MASK) && - !s->singlestep) { - /* jump to same page: we can use a direct jump */ - tcg_gen_goto_tb(tb_num); - tcg_gen_movi_tl(cpu_pc, pc); - tcg_gen_movi_tl(cpu_npc, npc); - tcg_gen_exit_tb((uintptr_t)tb + tb_num); - } else { - /* jump to another page: currently not optimized */ - tcg_gen_movi_tl(cpu_pc, pc); - tcg_gen_movi_tl(cpu_npc, npc); - tcg_gen_exit_tb(0); - } -} - -// XXX suboptimal -static inline void gen_mov_reg_N(TCGv reg, TCGv_i32 src) -{ - tcg_gen_extu_i32_tl(reg, src); - tcg_gen_shri_tl(reg, reg, PSR_NEG_SHIFT); - tcg_gen_andi_tl(reg, reg, 0x1); -} - -static inline void gen_mov_reg_Z(TCGv reg, TCGv_i32 src) -{ - tcg_gen_extu_i32_tl(reg, src); - tcg_gen_shri_tl(reg, reg, PSR_ZERO_SHIFT); - tcg_gen_andi_tl(reg, reg, 0x1); -} - -static inline void gen_mov_reg_V(TCGv reg, TCGv_i32 src) -{ - tcg_gen_extu_i32_tl(reg, src); - tcg_gen_shri_tl(reg, reg, PSR_OVF_SHIFT); - tcg_gen_andi_tl(reg, reg, 0x1); -} - -static inline void gen_mov_reg_C(TCGv reg, TCGv_i32 src) -{ - tcg_gen_extu_i32_tl(reg, src); - tcg_gen_shri_tl(reg, reg, PSR_CARRY_SHIFT); - tcg_gen_andi_tl(reg, reg, 0x1); -} - -static inline void gen_op_add_cc(TCGv dst, TCGv src1, TCGv src2) -{ - tcg_gen_mov_tl(cpu_cc_src, src1); - tcg_gen_mov_tl(cpu_cc_src2, src2); - tcg_gen_add_tl(cpu_cc_dst, cpu_cc_src, cpu_cc_src2); - tcg_gen_mov_tl(dst, cpu_cc_dst); -} - -static TCGv_i32 gen_add32_carry32(void) -{ - TCGv_i32 carry_32, cc_src1_32, cc_src2_32; - - /* Carry is computed from a previous add: (dst < src) */ -#if TARGET_LONG_BITS == 64 - cc_src1_32 = tcg_temp_new_i32(); - cc_src2_32 = tcg_temp_new_i32(); - tcg_gen_extrl_i64_i32(cc_src1_32, cpu_cc_dst); - tcg_gen_extrl_i64_i32(cc_src2_32, cpu_cc_src); -#else - cc_src1_32 = cpu_cc_dst; - cc_src2_32 = cpu_cc_src; -#endif - - carry_32 = tcg_temp_new_i32(); - tcg_gen_setcond_i32(TCG_COND_LTU, carry_32, cc_src1_32, cc_src2_32); - -#if TARGET_LONG_BITS == 64 - tcg_temp_free_i32(cc_src1_32); - tcg_temp_free_i32(cc_src2_32); -#endif - - return carry_32; -} - -static TCGv_i32 gen_sub32_carry32(void) -{ - TCGv_i32 carry_32, cc_src1_32, cc_src2_32; - - /* Carry is computed from a previous borrow: (src1 < src2) */ -#if TARGET_LONG_BITS == 64 - cc_src1_32 = tcg_temp_new_i32(); - cc_src2_32 = tcg_temp_new_i32(); - tcg_gen_extrl_i64_i32(cc_src1_32, cpu_cc_src); - tcg_gen_extrl_i64_i32(cc_src2_32, cpu_cc_src2); -#else - cc_src1_32 = cpu_cc_src; - cc_src2_32 = cpu_cc_src2; -#endif - - carry_32 = tcg_temp_new_i32(); - tcg_gen_setcond_i32(TCG_COND_LTU, carry_32, cc_src1_32, cc_src2_32); - -#if TARGET_LONG_BITS == 64 - tcg_temp_free_i32(cc_src1_32); - tcg_temp_free_i32(cc_src2_32); -#endif - - return carry_32; -} - -static void gen_op_addx_int(DisasContext *dc, TCGv dst, TCGv src1, - TCGv src2, int update_cc) -{ - TCGv_i32 carry_32; - TCGv carry; - - switch (dc->cc_op) { - case CC_OP_DIV: - case CC_OP_LOGIC: - /* Carry is known to be zero. Fall back to plain ADD. */ - if (update_cc) { - gen_op_add_cc(dst, src1, src2); - } else { - tcg_gen_add_tl(dst, src1, src2); - } - return; - - case CC_OP_ADD: - case CC_OP_TADD: - case CC_OP_TADDTV: - if (TARGET_LONG_BITS == 32) { - /* We can re-use the host's hardware carry generation by using - an ADD2 opcode. We discard the low part of the output. - Ideally we'd combine this operation with the add that - generated the carry in the first place. */ - carry = tcg_temp_new(); - tcg_gen_add2_tl(carry, dst, cpu_cc_src, src1, cpu_cc_src2, src2); - tcg_temp_free(carry); - goto add_done; - } - carry_32 = gen_add32_carry32(); - break; - - case CC_OP_SUB: - case CC_OP_TSUB: - case CC_OP_TSUBTV: - carry_32 = gen_sub32_carry32(); - break; - - default: - /* We need external help to produce the carry. */ - carry_32 = tcg_temp_new_i32(); - gen_helper_compute_C_icc(carry_32, cpu_env); - break; - } - -#if TARGET_LONG_BITS == 64 - carry = tcg_temp_new(); - tcg_gen_extu_i32_i64(carry, carry_32); -#else - carry = carry_32; -#endif - - tcg_gen_add_tl(dst, src1, src2); - tcg_gen_add_tl(dst, dst, carry); - - tcg_temp_free_i32(carry_32); -#if TARGET_LONG_BITS == 64 - tcg_temp_free(carry); -#endif - - add_done: - if (update_cc) { - tcg_gen_mov_tl(cpu_cc_src, src1); - tcg_gen_mov_tl(cpu_cc_src2, src2); - tcg_gen_mov_tl(cpu_cc_dst, dst); - tcg_gen_movi_i32(cpu_cc_op, CC_OP_ADDX); - dc->cc_op = CC_OP_ADDX; - } -} - -static inline void gen_op_sub_cc(TCGv dst, TCGv src1, TCGv src2) -{ - tcg_gen_mov_tl(cpu_cc_src, src1); - tcg_gen_mov_tl(cpu_cc_src2, src2); - tcg_gen_sub_tl(cpu_cc_dst, cpu_cc_src, cpu_cc_src2); - tcg_gen_mov_tl(dst, cpu_cc_dst); -} - -static void gen_op_subx_int(DisasContext *dc, TCGv dst, TCGv src1, - TCGv src2, int update_cc) -{ - TCGv_i32 carry_32; - TCGv carry; - - switch (dc->cc_op) { - case CC_OP_DIV: - case CC_OP_LOGIC: - /* Carry is known to be zero. Fall back to plain SUB. */ - if (update_cc) { - gen_op_sub_cc(dst, src1, src2); - } else { - tcg_gen_sub_tl(dst, src1, src2); - } - return; - - case CC_OP_ADD: - case CC_OP_TADD: - case CC_OP_TADDTV: - carry_32 = gen_add32_carry32(); - break; - - case CC_OP_SUB: - case CC_OP_TSUB: - case CC_OP_TSUBTV: - if (TARGET_LONG_BITS == 32) { - /* We can re-use the host's hardware carry generation by using - a SUB2 opcode. We discard the low part of the output. - Ideally we'd combine this operation with the add that - generated the carry in the first place. */ - carry = tcg_temp_new(); - tcg_gen_sub2_tl(carry, dst, cpu_cc_src, src1, cpu_cc_src2, src2); - tcg_temp_free(carry); - goto sub_done; - } - carry_32 = gen_sub32_carry32(); - break; - - default: - /* We need external help to produce the carry. */ - carry_32 = tcg_temp_new_i32(); - gen_helper_compute_C_icc(carry_32, cpu_env); - break; - } - -#if TARGET_LONG_BITS == 64 - carry = tcg_temp_new(); - tcg_gen_extu_i32_i64(carry, carry_32); -#else - carry = carry_32; -#endif - - tcg_gen_sub_tl(dst, src1, src2); - tcg_gen_sub_tl(dst, dst, carry); - - tcg_temp_free_i32(carry_32); -#if TARGET_LONG_BITS == 64 - tcg_temp_free(carry); -#endif - - sub_done: - if (update_cc) { - tcg_gen_mov_tl(cpu_cc_src, src1); - tcg_gen_mov_tl(cpu_cc_src2, src2); - tcg_gen_mov_tl(cpu_cc_dst, dst); - tcg_gen_movi_i32(cpu_cc_op, CC_OP_SUBX); - dc->cc_op = CC_OP_SUBX; - } -} - -static inline void gen_op_mulscc(TCGv dst, TCGv src1, TCGv src2) -{ - TCGv r_temp, zero, t0; - - r_temp = tcg_temp_new(); - t0 = tcg_temp_new(); - - /* old op: - if (!(env->y & 1)) - T1 = 0; - */ - zero = tcg_const_tl(0); - tcg_gen_andi_tl(cpu_cc_src, src1, 0xffffffff); - tcg_gen_andi_tl(r_temp, cpu_y, 0x1); - tcg_gen_andi_tl(cpu_cc_src2, src2, 0xffffffff); - tcg_gen_movcond_tl(TCG_COND_EQ, cpu_cc_src2, r_temp, zero, - zero, cpu_cc_src2); - tcg_temp_free(zero); - - // b2 = T0 & 1; - // env->y = (b2 << 31) | (env->y >> 1); - tcg_gen_andi_tl(r_temp, cpu_cc_src, 0x1); - tcg_gen_shli_tl(r_temp, r_temp, 31); - tcg_gen_shri_tl(t0, cpu_y, 1); - tcg_gen_andi_tl(t0, t0, 0x7fffffff); - tcg_gen_or_tl(t0, t0, r_temp); - tcg_gen_andi_tl(cpu_y, t0, 0xffffffff); - - // b1 = N ^ V; - gen_mov_reg_N(t0, cpu_psr); - gen_mov_reg_V(r_temp, cpu_psr); - tcg_gen_xor_tl(t0, t0, r_temp); - tcg_temp_free(r_temp); - - // T0 = (b1 << 31) | (T0 >> 1); - // src1 = T0; - tcg_gen_shli_tl(t0, t0, 31); - tcg_gen_shri_tl(cpu_cc_src, cpu_cc_src, 1); - tcg_gen_or_tl(cpu_cc_src, cpu_cc_src, t0); - tcg_temp_free(t0); - - tcg_gen_add_tl(cpu_cc_dst, cpu_cc_src, cpu_cc_src2); - - tcg_gen_mov_tl(dst, cpu_cc_dst); -} - -static inline void gen_op_multiply(TCGv dst, TCGv src1, TCGv src2, int sign_ext) -{ -#if TARGET_LONG_BITS == 32 - if (sign_ext) { - tcg_gen_muls2_tl(dst, cpu_y, src1, src2); - } else { - tcg_gen_mulu2_tl(dst, cpu_y, src1, src2); - } -#else - TCGv t0 = tcg_temp_new_i64(); - TCGv t1 = tcg_temp_new_i64(); - - if (sign_ext) { - tcg_gen_ext32s_i64(t0, src1); - tcg_gen_ext32s_i64(t1, src2); - } else { - tcg_gen_ext32u_i64(t0, src1); - tcg_gen_ext32u_i64(t1, src2); - } - - tcg_gen_mul_i64(dst, t0, t1); - tcg_temp_free(t0); - tcg_temp_free(t1); - - tcg_gen_shri_i64(cpu_y, dst, 32); -#endif -} - -static inline void gen_op_umul(TCGv dst, TCGv src1, TCGv src2) -{ - /* zero-extend truncated operands before multiplication */ - gen_op_multiply(dst, src1, src2, 0); -} - -static inline void gen_op_smul(TCGv dst, TCGv src1, TCGv src2) -{ - /* sign-extend truncated operands before multiplication */ - gen_op_multiply(dst, src1, src2, 1); -} - -// 1 -static inline void gen_op_eval_ba(TCGv dst) -{ - tcg_gen_movi_tl(dst, 1); -} - -// Z -static inline void gen_op_eval_be(TCGv dst, TCGv_i32 src) -{ - gen_mov_reg_Z(dst, src); -} - -// Z | (N ^ V) -static inline void gen_op_eval_ble(TCGv dst, TCGv_i32 src) -{ - TCGv t0 = tcg_temp_new(); - gen_mov_reg_N(t0, src); - gen_mov_reg_V(dst, src); - tcg_gen_xor_tl(dst, dst, t0); - gen_mov_reg_Z(t0, src); - tcg_gen_or_tl(dst, dst, t0); - tcg_temp_free(t0); -} - -// N ^ V -static inline void gen_op_eval_bl(TCGv dst, TCGv_i32 src) -{ - TCGv t0 = tcg_temp_new(); - gen_mov_reg_V(t0, src); - gen_mov_reg_N(dst, src); - tcg_gen_xor_tl(dst, dst, t0); - tcg_temp_free(t0); -} - -// C | Z -static inline void gen_op_eval_bleu(TCGv dst, TCGv_i32 src) -{ - TCGv t0 = tcg_temp_new(); - gen_mov_reg_Z(t0, src); - gen_mov_reg_C(dst, src); - tcg_gen_or_tl(dst, dst, t0); - tcg_temp_free(t0); -} - -// C -static inline void gen_op_eval_bcs(TCGv dst, TCGv_i32 src) -{ - gen_mov_reg_C(dst, src); -} - -// V -static inline void gen_op_eval_bvs(TCGv dst, TCGv_i32 src) -{ - gen_mov_reg_V(dst, src); -} - -// 0 -static inline void gen_op_eval_bn(TCGv dst) -{ - tcg_gen_movi_tl(dst, 0); -} - -// N -static inline void gen_op_eval_bneg(TCGv dst, TCGv_i32 src) -{ - gen_mov_reg_N(dst, src); -} - -// !Z -static inline void gen_op_eval_bne(TCGv dst, TCGv_i32 src) -{ - gen_mov_reg_Z(dst, src); - tcg_gen_xori_tl(dst, dst, 0x1); -} - -// !(Z | (N ^ V)) -static inline void gen_op_eval_bg(TCGv dst, TCGv_i32 src) -{ - gen_op_eval_ble(dst, src); - tcg_gen_xori_tl(dst, dst, 0x1); -} - -// !(N ^ V) -static inline void gen_op_eval_bge(TCGv dst, TCGv_i32 src) -{ - gen_op_eval_bl(dst, src); - tcg_gen_xori_tl(dst, dst, 0x1); -} - -// !(C | Z) -static inline void gen_op_eval_bgu(TCGv dst, TCGv_i32 src) -{ - gen_op_eval_bleu(dst, src); - tcg_gen_xori_tl(dst, dst, 0x1); -} - -// !C -static inline void gen_op_eval_bcc(TCGv dst, TCGv_i32 src) -{ - gen_mov_reg_C(dst, src); - tcg_gen_xori_tl(dst, dst, 0x1); -} - -// !N -static inline void gen_op_eval_bpos(TCGv dst, TCGv_i32 src) -{ - gen_mov_reg_N(dst, src); - tcg_gen_xori_tl(dst, dst, 0x1); -} - -// !V -static inline void gen_op_eval_bvc(TCGv dst, TCGv_i32 src) -{ - gen_mov_reg_V(dst, src); - tcg_gen_xori_tl(dst, dst, 0x1); -} - -/* - FPSR bit field FCC1 | FCC0: - 0 = - 1 < - 2 > - 3 unordered -*/ -static inline void gen_mov_reg_FCC0(TCGv reg, TCGv src, - unsigned int fcc_offset) -{ - tcg_gen_shri_tl(reg, src, FSR_FCC0_SHIFT + fcc_offset); - tcg_gen_andi_tl(reg, reg, 0x1); -} - -static inline void gen_mov_reg_FCC1(TCGv reg, TCGv src, - unsigned int fcc_offset) -{ - tcg_gen_shri_tl(reg, src, FSR_FCC1_SHIFT + fcc_offset); - tcg_gen_andi_tl(reg, reg, 0x1); -} - -// !0: FCC0 | FCC1 -static inline void gen_op_eval_fbne(TCGv dst, TCGv src, - unsigned int fcc_offset) -{ - TCGv t0 = tcg_temp_new(); - gen_mov_reg_FCC0(dst, src, fcc_offset); - gen_mov_reg_FCC1(t0, src, fcc_offset); - tcg_gen_or_tl(dst, dst, t0); - tcg_temp_free(t0); -} - -// 1 or 2: FCC0 ^ FCC1 -static inline void gen_op_eval_fblg(TCGv dst, TCGv src, - unsigned int fcc_offset) -{ - TCGv t0 = tcg_temp_new(); - gen_mov_reg_FCC0(dst, src, fcc_offset); - gen_mov_reg_FCC1(t0, src, fcc_offset); - tcg_gen_xor_tl(dst, dst, t0); - tcg_temp_free(t0); -} - -// 1 or 3: FCC0 -static inline void gen_op_eval_fbul(TCGv dst, TCGv src, - unsigned int fcc_offset) -{ - gen_mov_reg_FCC0(dst, src, fcc_offset); -} - -// 1: FCC0 & !FCC1 -static inline void gen_op_eval_fbl(TCGv dst, TCGv src, - unsigned int fcc_offset) -{ - TCGv t0 = tcg_temp_new(); - gen_mov_reg_FCC0(dst, src, fcc_offset); - gen_mov_reg_FCC1(t0, src, fcc_offset); - tcg_gen_andc_tl(dst, dst, t0); - tcg_temp_free(t0); -} - -// 2 or 3: FCC1 -static inline void gen_op_eval_fbug(TCGv dst, TCGv src, - unsigned int fcc_offset) -{ - gen_mov_reg_FCC1(dst, src, fcc_offset); -} - -// 2: !FCC0 & FCC1 -static inline void gen_op_eval_fbg(TCGv dst, TCGv src, - unsigned int fcc_offset) -{ - TCGv t0 = tcg_temp_new(); - gen_mov_reg_FCC0(dst, src, fcc_offset); - gen_mov_reg_FCC1(t0, src, fcc_offset); - tcg_gen_andc_tl(dst, t0, dst); - tcg_temp_free(t0); -} - -// 3: FCC0 & FCC1 -static inline void gen_op_eval_fbu(TCGv dst, TCGv src, - unsigned int fcc_offset) -{ - TCGv t0 = tcg_temp_new(); - gen_mov_reg_FCC0(dst, src, fcc_offset); - gen_mov_reg_FCC1(t0, src, fcc_offset); - tcg_gen_and_tl(dst, dst, t0); - tcg_temp_free(t0); -} - -// 0: !(FCC0 | FCC1) -static inline void gen_op_eval_fbe(TCGv dst, TCGv src, - unsigned int fcc_offset) -{ - TCGv t0 = tcg_temp_new(); - gen_mov_reg_FCC0(dst, src, fcc_offset); - gen_mov_reg_FCC1(t0, src, fcc_offset); - tcg_gen_or_tl(dst, dst, t0); - tcg_gen_xori_tl(dst, dst, 0x1); - tcg_temp_free(t0); -} - -// 0 or 3: !(FCC0 ^ FCC1) -static inline void gen_op_eval_fbue(TCGv dst, TCGv src, - unsigned int fcc_offset) -{ - TCGv t0 = tcg_temp_new(); - gen_mov_reg_FCC0(dst, src, fcc_offset); - gen_mov_reg_FCC1(t0, src, fcc_offset); - tcg_gen_xor_tl(dst, dst, t0); - tcg_gen_xori_tl(dst, dst, 0x1); - tcg_temp_free(t0); -} - -// 0 or 2: !FCC0 -static inline void gen_op_eval_fbge(TCGv dst, TCGv src, - unsigned int fcc_offset) -{ - gen_mov_reg_FCC0(dst, src, fcc_offset); - tcg_gen_xori_tl(dst, dst, 0x1); -} - -// !1: !(FCC0 & !FCC1) -static inline void gen_op_eval_fbuge(TCGv dst, TCGv src, - unsigned int fcc_offset) -{ - TCGv t0 = tcg_temp_new(); - gen_mov_reg_FCC0(dst, src, fcc_offset); - gen_mov_reg_FCC1(t0, src, fcc_offset); - tcg_gen_andc_tl(dst, dst, t0); - tcg_gen_xori_tl(dst, dst, 0x1); - tcg_temp_free(t0); -} - -// 0 or 1: !FCC1 -static inline void gen_op_eval_fble(TCGv dst, TCGv src, - unsigned int fcc_offset) -{ - gen_mov_reg_FCC1(dst, src, fcc_offset); - tcg_gen_xori_tl(dst, dst, 0x1); -} - -// !2: !(!FCC0 & FCC1) -static inline void gen_op_eval_fbule(TCGv dst, TCGv src, - unsigned int fcc_offset) -{ - TCGv t0 = tcg_temp_new(); - gen_mov_reg_FCC0(dst, src, fcc_offset); - gen_mov_reg_FCC1(t0, src, fcc_offset); - tcg_gen_andc_tl(dst, t0, dst); - tcg_gen_xori_tl(dst, dst, 0x1); - tcg_temp_free(t0); -} - -// !3: !(FCC0 & FCC1) -static inline void gen_op_eval_fbo(TCGv dst, TCGv src, - unsigned int fcc_offset) -{ - TCGv t0 = tcg_temp_new(); - gen_mov_reg_FCC0(dst, src, fcc_offset); - gen_mov_reg_FCC1(t0, src, fcc_offset); - tcg_gen_and_tl(dst, dst, t0); - tcg_gen_xori_tl(dst, dst, 0x1); - tcg_temp_free(t0); -} - -static inline void gen_branch2(DisasContext *dc, target_ulong pc1, - target_ulong pc2, TCGv r_cond) -{ - TCGLabel *l1 = gen_new_label(); - - tcg_gen_brcondi_tl(TCG_COND_EQ, r_cond, 0, l1); - - gen_goto_tb(dc, 0, pc1, pc1 + 4); - - gen_set_label(l1); - gen_goto_tb(dc, 1, pc2, pc2 + 4); -} - -static void gen_branch_a(DisasContext *dc, target_ulong pc1) -{ - TCGLabel *l1 = gen_new_label(); - target_ulong npc = dc->npc; - - tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_cond, 0, l1); - - gen_goto_tb(dc, 0, npc, pc1); - - gen_set_label(l1); - gen_goto_tb(dc, 1, npc + 4, npc + 8); - - dc->is_br = 1; -} - -static void gen_branch_n(DisasContext *dc, target_ulong pc1) -{ - target_ulong npc = dc->npc; - - if (likely(npc != DYNAMIC_PC)) { - dc->pc = npc; - dc->jump_pc[0] = pc1; - dc->jump_pc[1] = npc + 4; - dc->npc = JUMP_PC; - } else { - TCGv t, z; - - tcg_gen_mov_tl(cpu_pc, cpu_npc); - - tcg_gen_addi_tl(cpu_npc, cpu_npc, 4); - t = tcg_const_tl(pc1); - z = tcg_const_tl(0); - tcg_gen_movcond_tl(TCG_COND_NE, cpu_npc, cpu_cond, z, t, cpu_npc); - tcg_temp_free(t); - tcg_temp_free(z); - - dc->pc = DYNAMIC_PC; - } -} - -static inline void gen_generic_branch(DisasContext *dc) -{ - TCGv npc0 = tcg_const_tl(dc->jump_pc[0]); - TCGv npc1 = tcg_const_tl(dc->jump_pc[1]); - TCGv zero = tcg_const_tl(0); - - tcg_gen_movcond_tl(TCG_COND_NE, cpu_npc, cpu_cond, zero, npc0, npc1); - - tcg_temp_free(npc0); - tcg_temp_free(npc1); - tcg_temp_free(zero); -} - -/* call this function before using the condition register as it may - have been set for a jump */ -static inline void flush_cond(DisasContext *dc) -{ - if (dc->npc == JUMP_PC) { - gen_generic_branch(dc); - dc->npc = DYNAMIC_PC; - } -} - -static inline void save_npc(DisasContext *dc) -{ - if (dc->npc == JUMP_PC) { - gen_generic_branch(dc); - dc->npc = DYNAMIC_PC; - } else if (dc->npc != DYNAMIC_PC) { - tcg_gen_movi_tl(cpu_npc, dc->npc); - } -} - -static inline void update_psr(DisasContext *dc) -{ - if (dc->cc_op != CC_OP_FLAGS) { - dc->cc_op = CC_OP_FLAGS; - gen_helper_compute_psr(cpu_env); - } -} - -static inline void save_state(DisasContext *dc) -{ - tcg_gen_movi_tl(cpu_pc, dc->pc); - save_npc(dc); -} - -static inline void gen_mov_pc_npc(DisasContext *dc) -{ - if (dc->npc == JUMP_PC) { - gen_generic_branch(dc); - tcg_gen_mov_tl(cpu_pc, cpu_npc); - dc->pc = DYNAMIC_PC; - } else if (dc->npc == DYNAMIC_PC) { - tcg_gen_mov_tl(cpu_pc, cpu_npc); - dc->pc = DYNAMIC_PC; - } else { - dc->pc = dc->npc; - } -} - -static inline void gen_op_next_insn(void) -{ - tcg_gen_mov_tl(cpu_pc, cpu_npc); - tcg_gen_addi_tl(cpu_npc, cpu_npc, 4); -} - -static void free_compare(DisasCompare *cmp) -{ - if (!cmp->g1) { - tcg_temp_free(cmp->c1); - } - if (!cmp->g2) { - tcg_temp_free(cmp->c2); - } -} - -static void gen_compare(DisasCompare *cmp, bool xcc, unsigned int cond, - DisasContext *dc) -{ - static int subcc_cond[16] = { - TCG_COND_NEVER, - TCG_COND_EQ, - TCG_COND_LE, - TCG_COND_LT, - TCG_COND_LEU, - TCG_COND_LTU, - -1, /* neg */ - -1, /* overflow */ - TCG_COND_ALWAYS, - TCG_COND_NE, - TCG_COND_GT, - TCG_COND_GE, - TCG_COND_GTU, - TCG_COND_GEU, - -1, /* pos */ - -1, /* no overflow */ - }; - - static int logic_cond[16] = { - TCG_COND_NEVER, - TCG_COND_EQ, /* eq: Z */ - TCG_COND_LE, /* le: Z | (N ^ V) -> Z | N */ - TCG_COND_LT, /* lt: N ^ V -> N */ - TCG_COND_EQ, /* leu: C | Z -> Z */ - TCG_COND_NEVER, /* ltu: C -> 0 */ - TCG_COND_LT, /* neg: N */ - TCG_COND_NEVER, /* vs: V -> 0 */ - TCG_COND_ALWAYS, - TCG_COND_NE, /* ne: !Z */ - TCG_COND_GT, /* gt: !(Z | (N ^ V)) -> !(Z | N) */ - TCG_COND_GE, /* ge: !(N ^ V) -> !N */ - TCG_COND_NE, /* gtu: !(C | Z) -> !Z */ - TCG_COND_ALWAYS, /* geu: !C -> 1 */ - TCG_COND_GE, /* pos: !N */ - TCG_COND_ALWAYS, /* vc: !V -> 1 */ - }; - - TCGv_i32 r_src; - TCGv r_dst; - -#ifdef TARGET_SPARC64 - if (xcc) { - r_src = cpu_xcc; - } else { - r_src = cpu_psr; - } -#else - r_src = cpu_psr; -#endif - - switch (dc->cc_op) { - case CC_OP_LOGIC: - cmp->cond = logic_cond[cond]; - do_compare_dst_0: - cmp->is_bool = false; - cmp->g2 = false; - cmp->c2 = tcg_const_tl(0); -#ifdef TARGET_SPARC64 - if (!xcc) { - cmp->g1 = false; - cmp->c1 = tcg_temp_new(); - tcg_gen_ext32s_tl(cmp->c1, cpu_cc_dst); - break; - } -#endif - cmp->g1 = true; - cmp->c1 = cpu_cc_dst; - break; - - case CC_OP_SUB: - switch (cond) { - case 6: /* neg */ - case 14: /* pos */ - cmp->cond = (cond == 6 ? TCG_COND_LT : TCG_COND_GE); - goto do_compare_dst_0; - - case 7: /* overflow */ - case 15: /* !overflow */ - goto do_dynamic; - - default: - cmp->cond = subcc_cond[cond]; - cmp->is_bool = false; -#ifdef TARGET_SPARC64 - if (!xcc) { - /* Note that sign-extension works for unsigned compares as - long as both operands are sign-extended. */ - cmp->g1 = cmp->g2 = false; - cmp->c1 = tcg_temp_new(); - cmp->c2 = tcg_temp_new(); - tcg_gen_ext32s_tl(cmp->c1, cpu_cc_src); - tcg_gen_ext32s_tl(cmp->c2, cpu_cc_src2); - break; - } -#endif - cmp->g1 = cmp->g2 = true; - cmp->c1 = cpu_cc_src; - cmp->c2 = cpu_cc_src2; - break; - } - break; - - default: - do_dynamic: - gen_helper_compute_psr(cpu_env); - dc->cc_op = CC_OP_FLAGS; - /* FALLTHRU */ - - case CC_OP_FLAGS: - /* We're going to generate a boolean result. */ - cmp->cond = TCG_COND_NE; - cmp->is_bool = true; - cmp->g1 = cmp->g2 = false; - cmp->c1 = r_dst = tcg_temp_new(); - cmp->c2 = tcg_const_tl(0); - - switch (cond) { - case 0x0: - gen_op_eval_bn(r_dst); - break; - case 0x1: - gen_op_eval_be(r_dst, r_src); - break; - case 0x2: - gen_op_eval_ble(r_dst, r_src); - break; - case 0x3: - gen_op_eval_bl(r_dst, r_src); - break; - case 0x4: - gen_op_eval_bleu(r_dst, r_src); - break; - case 0x5: - gen_op_eval_bcs(r_dst, r_src); - break; - case 0x6: - gen_op_eval_bneg(r_dst, r_src); - break; - case 0x7: - gen_op_eval_bvs(r_dst, r_src); - break; - case 0x8: - gen_op_eval_ba(r_dst); - break; - case 0x9: - gen_op_eval_bne(r_dst, r_src); - break; - case 0xa: - gen_op_eval_bg(r_dst, r_src); - break; - case 0xb: - gen_op_eval_bge(r_dst, r_src); - break; - case 0xc: - gen_op_eval_bgu(r_dst, r_src); - break; - case 0xd: - gen_op_eval_bcc(r_dst, r_src); - break; - case 0xe: - gen_op_eval_bpos(r_dst, r_src); - break; - case 0xf: - gen_op_eval_bvc(r_dst, r_src); - break; - } - break; - } -} - -static void gen_fcompare(DisasCompare *cmp, unsigned int cc, unsigned int cond) -{ - unsigned int offset; - TCGv r_dst; - - /* For now we still generate a straight boolean result. */ - cmp->cond = TCG_COND_NE; - cmp->is_bool = true; - cmp->g1 = cmp->g2 = false; - cmp->c1 = r_dst = tcg_temp_new(); - cmp->c2 = tcg_const_tl(0); - - switch (cc) { - default: - case 0x0: - offset = 0; - break; - case 0x1: - offset = 32 - 10; - break; - case 0x2: - offset = 34 - 10; - break; - case 0x3: - offset = 36 - 10; - break; - } - - switch (cond) { - case 0x0: - gen_op_eval_bn(r_dst); - break; - case 0x1: - gen_op_eval_fbne(r_dst, cpu_fsr, offset); - break; - case 0x2: - gen_op_eval_fblg(r_dst, cpu_fsr, offset); - break; - case 0x3: - gen_op_eval_fbul(r_dst, cpu_fsr, offset); - break; - case 0x4: - gen_op_eval_fbl(r_dst, cpu_fsr, offset); - break; - case 0x5: - gen_op_eval_fbug(r_dst, cpu_fsr, offset); - break; - case 0x6: - gen_op_eval_fbg(r_dst, cpu_fsr, offset); - break; - case 0x7: - gen_op_eval_fbu(r_dst, cpu_fsr, offset); - break; - case 0x8: - gen_op_eval_ba(r_dst); - break; - case 0x9: - gen_op_eval_fbe(r_dst, cpu_fsr, offset); - break; - case 0xa: - gen_op_eval_fbue(r_dst, cpu_fsr, offset); - break; - case 0xb: - gen_op_eval_fbge(r_dst, cpu_fsr, offset); - break; - case 0xc: - gen_op_eval_fbuge(r_dst, cpu_fsr, offset); - break; - case 0xd: - gen_op_eval_fble(r_dst, cpu_fsr, offset); - break; - case 0xe: - gen_op_eval_fbule(r_dst, cpu_fsr, offset); - break; - case 0xf: - gen_op_eval_fbo(r_dst, cpu_fsr, offset); - break; - } -} - -static void gen_cond(TCGv r_dst, unsigned int cc, unsigned int cond, - DisasContext *dc) -{ - DisasCompare cmp; - gen_compare(&cmp, cc, cond, dc); - - /* The interface is to return a boolean in r_dst. */ - if (cmp.is_bool) { - tcg_gen_mov_tl(r_dst, cmp.c1); - } else { - tcg_gen_setcond_tl(cmp.cond, r_dst, cmp.c1, cmp.c2); - } - - free_compare(&cmp); -} - -static void gen_fcond(TCGv r_dst, unsigned int cc, unsigned int cond) -{ - DisasCompare cmp; - gen_fcompare(&cmp, cc, cond); - - /* The interface is to return a boolean in r_dst. */ - if (cmp.is_bool) { - tcg_gen_mov_tl(r_dst, cmp.c1); - } else { - tcg_gen_setcond_tl(cmp.cond, r_dst, cmp.c1, cmp.c2); - } - - free_compare(&cmp); -} - -#ifdef TARGET_SPARC64 -// Inverted logic -static const int gen_tcg_cond_reg[8] = { - -1, - TCG_COND_NE, - TCG_COND_GT, - TCG_COND_GE, - -1, - TCG_COND_EQ, - TCG_COND_LE, - TCG_COND_LT, -}; - -static void gen_compare_reg(DisasCompare *cmp, int cond, TCGv r_src) -{ - cmp->cond = tcg_invert_cond(gen_tcg_cond_reg[cond]); - cmp->is_bool = false; - cmp->g1 = true; - cmp->g2 = false; - cmp->c1 = r_src; - cmp->c2 = tcg_const_tl(0); -} - -static inline void gen_cond_reg(TCGv r_dst, int cond, TCGv r_src) -{ - DisasCompare cmp; - gen_compare_reg(&cmp, cond, r_src); - - /* The interface is to return a boolean in r_dst. */ - tcg_gen_setcond_tl(cmp.cond, r_dst, cmp.c1, cmp.c2); - - free_compare(&cmp); -} -#endif - -static void do_branch(DisasContext *dc, int32_t offset, uint32_t insn, int cc) -{ - unsigned int cond = GET_FIELD(insn, 3, 6), a = (insn & (1 << 29)); - target_ulong target = dc->pc + offset; - -#ifdef TARGET_SPARC64 - if (unlikely(AM_CHECK(dc))) { - target &= 0xffffffffULL; - } -#endif - if (cond == 0x0) { - /* unconditional not taken */ - if (a) { - dc->pc = dc->npc + 4; - dc->npc = dc->pc + 4; - } else { - dc->pc = dc->npc; - dc->npc = dc->pc + 4; - } - } else if (cond == 0x8) { - /* unconditional taken */ - if (a) { - dc->pc = target; - dc->npc = dc->pc + 4; - } else { - dc->pc = dc->npc; - dc->npc = target; - tcg_gen_mov_tl(cpu_pc, cpu_npc); - } - } else { - flush_cond(dc); - gen_cond(cpu_cond, cc, cond, dc); - if (a) { - gen_branch_a(dc, target); - } else { - gen_branch_n(dc, target); - } - } -} - -static void do_fbranch(DisasContext *dc, int32_t offset, uint32_t insn, int cc) -{ - unsigned int cond = GET_FIELD(insn, 3, 6), a = (insn & (1 << 29)); - target_ulong target = dc->pc + offset; - -#ifdef TARGET_SPARC64 - if (unlikely(AM_CHECK(dc))) { - target &= 0xffffffffULL; - } -#endif - if (cond == 0x0) { - /* unconditional not taken */ - if (a) { - dc->pc = dc->npc + 4; - dc->npc = dc->pc + 4; - } else { - dc->pc = dc->npc; - dc->npc = dc->pc + 4; - } - } else if (cond == 0x8) { - /* unconditional taken */ - if (a) { - dc->pc = target; - dc->npc = dc->pc + 4; - } else { - dc->pc = dc->npc; - dc->npc = target; - tcg_gen_mov_tl(cpu_pc, cpu_npc); - } - } else { - flush_cond(dc); - gen_fcond(cpu_cond, cc, cond); - if (a) { - gen_branch_a(dc, target); - } else { - gen_branch_n(dc, target); - } - } -} - -#ifdef TARGET_SPARC64 -static void do_branch_reg(DisasContext *dc, int32_t offset, uint32_t insn, - TCGv r_reg) -{ - unsigned int cond = GET_FIELD_SP(insn, 25, 27), a = (insn & (1 << 29)); - target_ulong target = dc->pc + offset; - - if (unlikely(AM_CHECK(dc))) { - target &= 0xffffffffULL; - } - flush_cond(dc); - gen_cond_reg(cpu_cond, cond, r_reg); - if (a) { - gen_branch_a(dc, target); - } else { - gen_branch_n(dc, target); - } -} - -static inline void gen_op_fcmps(int fccno, TCGv_i32 r_rs1, TCGv_i32 r_rs2) -{ - switch (fccno) { - case 0: - gen_helper_fcmps(cpu_env, r_rs1, r_rs2); - break; - case 1: - gen_helper_fcmps_fcc1(cpu_env, r_rs1, r_rs2); - break; - case 2: - gen_helper_fcmps_fcc2(cpu_env, r_rs1, r_rs2); - break; - case 3: - gen_helper_fcmps_fcc3(cpu_env, r_rs1, r_rs2); - break; - } -} - -static inline void gen_op_fcmpd(int fccno, TCGv_i64 r_rs1, TCGv_i64 r_rs2) -{ - switch (fccno) { - case 0: - gen_helper_fcmpd(cpu_env, r_rs1, r_rs2); - break; - case 1: - gen_helper_fcmpd_fcc1(cpu_env, r_rs1, r_rs2); - break; - case 2: - gen_helper_fcmpd_fcc2(cpu_env, r_rs1, r_rs2); - break; - case 3: - gen_helper_fcmpd_fcc3(cpu_env, r_rs1, r_rs2); - break; - } -} - -static inline void gen_op_fcmpq(int fccno) -{ - switch (fccno) { - case 0: - gen_helper_fcmpq(cpu_env); - break; - case 1: - gen_helper_fcmpq_fcc1(cpu_env); - break; - case 2: - gen_helper_fcmpq_fcc2(cpu_env); - break; - case 3: - gen_helper_fcmpq_fcc3(cpu_env); - break; - } -} - -static inline void gen_op_fcmpes(int fccno, TCGv_i32 r_rs1, TCGv_i32 r_rs2) -{ - switch (fccno) { - case 0: - gen_helper_fcmpes(cpu_env, r_rs1, r_rs2); - break; - case 1: - gen_helper_fcmpes_fcc1(cpu_env, r_rs1, r_rs2); - break; - case 2: - gen_helper_fcmpes_fcc2(cpu_env, r_rs1, r_rs2); - break; - case 3: - gen_helper_fcmpes_fcc3(cpu_env, r_rs1, r_rs2); - break; - } -} - -static inline void gen_op_fcmped(int fccno, TCGv_i64 r_rs1, TCGv_i64 r_rs2) -{ - switch (fccno) { - case 0: - gen_helper_fcmped(cpu_env, r_rs1, r_rs2); - break; - case 1: - gen_helper_fcmped_fcc1(cpu_env, r_rs1, r_rs2); - break; - case 2: - gen_helper_fcmped_fcc2(cpu_env, r_rs1, r_rs2); - break; - case 3: - gen_helper_fcmped_fcc3(cpu_env, r_rs1, r_rs2); - break; - } -} - -static inline void gen_op_fcmpeq(int fccno) -{ - switch (fccno) { - case 0: - gen_helper_fcmpeq(cpu_env); - break; - case 1: - gen_helper_fcmpeq_fcc1(cpu_env); - break; - case 2: - gen_helper_fcmpeq_fcc2(cpu_env); - break; - case 3: - gen_helper_fcmpeq_fcc3(cpu_env); - break; - } -} - -#else - -static inline void gen_op_fcmps(int fccno, TCGv r_rs1, TCGv r_rs2) -{ - gen_helper_fcmps(cpu_env, r_rs1, r_rs2); -} - -static inline void gen_op_fcmpd(int fccno, TCGv_i64 r_rs1, TCGv_i64 r_rs2) -{ - gen_helper_fcmpd(cpu_env, r_rs1, r_rs2); -} - -static inline void gen_op_fcmpq(int fccno) -{ - gen_helper_fcmpq(cpu_env); -} - -static inline void gen_op_fcmpes(int fccno, TCGv r_rs1, TCGv r_rs2) -{ - gen_helper_fcmpes(cpu_env, r_rs1, r_rs2); -} - -static inline void gen_op_fcmped(int fccno, TCGv_i64 r_rs1, TCGv_i64 r_rs2) -{ - gen_helper_fcmped(cpu_env, r_rs1, r_rs2); -} - -static inline void gen_op_fcmpeq(int fccno) -{ - gen_helper_fcmpeq(cpu_env); -} -#endif - -static inline void gen_op_fpexception_im(int fsr_flags) -{ - TCGv_i32 r_const; - - tcg_gen_andi_tl(cpu_fsr, cpu_fsr, FSR_FTT_NMASK); - tcg_gen_ori_tl(cpu_fsr, cpu_fsr, fsr_flags); - r_const = tcg_const_i32(TT_FP_EXCP); - gen_helper_raise_exception(cpu_env, r_const); - tcg_temp_free_i32(r_const); -} - -static int gen_trap_ifnofpu(DisasContext *dc) -{ -#if !defined(CONFIG_USER_ONLY) - if (!dc->fpu_enabled) { - TCGv_i32 r_const; - - save_state(dc); - r_const = tcg_const_i32(TT_NFPU_INSN); - gen_helper_raise_exception(cpu_env, r_const); - tcg_temp_free_i32(r_const); - dc->is_br = 1; - return 1; - } -#endif - return 0; -} - -static inline void gen_op_clear_ieee_excp_and_FTT(void) -{ - tcg_gen_andi_tl(cpu_fsr, cpu_fsr, FSR_FTT_CEXC_NMASK); -} - -static inline void gen_fop_FF(DisasContext *dc, int rd, int rs, - void (*gen)(TCGv_i32, TCGv_ptr, TCGv_i32)) -{ - TCGv_i32 dst, src; - - src = gen_load_fpr_F(dc, rs); - dst = gen_dest_fpr_F(dc); - - gen(dst, cpu_env, src); - - gen_store_fpr_F(dc, rd, dst); -} - -static inline void gen_ne_fop_FF(DisasContext *dc, int rd, int rs, - void (*gen)(TCGv_i32, TCGv_i32)) -{ - TCGv_i32 dst, src; - - src = gen_load_fpr_F(dc, rs); - dst = gen_dest_fpr_F(dc); - - gen(dst, src); - - gen_store_fpr_F(dc, rd, dst); -} - -static inline void gen_fop_FFF(DisasContext *dc, int rd, int rs1, int rs2, - void (*gen)(TCGv_i32, TCGv_ptr, TCGv_i32, TCGv_i32)) -{ - TCGv_i32 dst, src1, src2; - - src1 = gen_load_fpr_F(dc, rs1); - src2 = gen_load_fpr_F(dc, rs2); - dst = gen_dest_fpr_F(dc); - - gen(dst, cpu_env, src1, src2); - - gen_store_fpr_F(dc, rd, dst); -} - -#ifdef TARGET_SPARC64 -static inline void gen_ne_fop_FFF(DisasContext *dc, int rd, int rs1, int rs2, - void (*gen)(TCGv_i32, TCGv_i32, TCGv_i32)) -{ - TCGv_i32 dst, src1, src2; - - src1 = gen_load_fpr_F(dc, rs1); - src2 = gen_load_fpr_F(dc, rs2); - dst = gen_dest_fpr_F(dc); - - gen(dst, src1, src2); - - gen_store_fpr_F(dc, rd, dst); -} -#endif - -static inline void gen_fop_DD(DisasContext *dc, int rd, int rs, - void (*gen)(TCGv_i64, TCGv_ptr, TCGv_i64)) -{ - TCGv_i64 dst, src; - - src = gen_load_fpr_D(dc, rs); - dst = gen_dest_fpr_D(dc, rd); - - gen(dst, cpu_env, src); - - gen_store_fpr_D(dc, rd, dst); -} - -#ifdef TARGET_SPARC64 -static inline void gen_ne_fop_DD(DisasContext *dc, int rd, int rs, - void (*gen)(TCGv_i64, TCGv_i64)) -{ - TCGv_i64 dst, src; - - src = gen_load_fpr_D(dc, rs); - dst = gen_dest_fpr_D(dc, rd); - - gen(dst, src); - - gen_store_fpr_D(dc, rd, dst); -} -#endif - -static inline void gen_fop_DDD(DisasContext *dc, int rd, int rs1, int rs2, - void (*gen)(TCGv_i64, TCGv_ptr, TCGv_i64, TCGv_i64)) -{ - TCGv_i64 dst, src1, src2; - - src1 = gen_load_fpr_D(dc, rs1); - src2 = gen_load_fpr_D(dc, rs2); - dst = gen_dest_fpr_D(dc, rd); - - gen(dst, cpu_env, src1, src2); - - gen_store_fpr_D(dc, rd, dst); -} - -#ifdef TARGET_SPARC64 -static inline void gen_ne_fop_DDD(DisasContext *dc, int rd, int rs1, int rs2, - void (*gen)(TCGv_i64, TCGv_i64, TCGv_i64)) -{ - TCGv_i64 dst, src1, src2; - - src1 = gen_load_fpr_D(dc, rs1); - src2 = gen_load_fpr_D(dc, rs2); - dst = gen_dest_fpr_D(dc, rd); - - gen(dst, src1, src2); - - gen_store_fpr_D(dc, rd, dst); -} - -static inline void gen_gsr_fop_DDD(DisasContext *dc, int rd, int rs1, int rs2, - void (*gen)(TCGv_i64, TCGv_i64, TCGv_i64, TCGv_i64)) -{ - TCGv_i64 dst, src1, src2; - - src1 = gen_load_fpr_D(dc, rs1); - src2 = gen_load_fpr_D(dc, rs2); - dst = gen_dest_fpr_D(dc, rd); - - gen(dst, cpu_gsr, src1, src2); - - gen_store_fpr_D(dc, rd, dst); -} - -static inline void gen_ne_fop_DDDD(DisasContext *dc, int rd, int rs1, int rs2, - void (*gen)(TCGv_i64, TCGv_i64, TCGv_i64, TCGv_i64)) -{ - TCGv_i64 dst, src0, src1, src2; - - src1 = gen_load_fpr_D(dc, rs1); - src2 = gen_load_fpr_D(dc, rs2); - src0 = gen_load_fpr_D(dc, rd); - dst = gen_dest_fpr_D(dc, rd); - - gen(dst, src0, src1, src2); - - gen_store_fpr_D(dc, rd, dst); -} -#endif - -static inline void gen_fop_QQ(DisasContext *dc, int rd, int rs, - void (*gen)(TCGv_ptr)) -{ - gen_op_load_fpr_QT1(QFPREG(rs)); - - gen(cpu_env); - - gen_op_store_QT0_fpr(QFPREG(rd)); - gen_update_fprs_dirty(QFPREG(rd)); -} - -#ifdef TARGET_SPARC64 -static inline void gen_ne_fop_QQ(DisasContext *dc, int rd, int rs, - void (*gen)(TCGv_ptr)) -{ - gen_op_load_fpr_QT1(QFPREG(rs)); - - gen(cpu_env); - - gen_op_store_QT0_fpr(QFPREG(rd)); - gen_update_fprs_dirty(QFPREG(rd)); -} -#endif - -static inline void gen_fop_QQQ(DisasContext *dc, int rd, int rs1, int rs2, - void (*gen)(TCGv_ptr)) -{ - gen_op_load_fpr_QT0(QFPREG(rs1)); - gen_op_load_fpr_QT1(QFPREG(rs2)); - - gen(cpu_env); - - gen_op_store_QT0_fpr(QFPREG(rd)); - gen_update_fprs_dirty(QFPREG(rd)); -} - -static inline void gen_fop_DFF(DisasContext *dc, int rd, int rs1, int rs2, - void (*gen)(TCGv_i64, TCGv_ptr, TCGv_i32, TCGv_i32)) -{ - TCGv_i64 dst; - TCGv_i32 src1, src2; - - src1 = gen_load_fpr_F(dc, rs1); - src2 = gen_load_fpr_F(dc, rs2); - dst = gen_dest_fpr_D(dc, rd); - - gen(dst, cpu_env, src1, src2); - - gen_store_fpr_D(dc, rd, dst); -} - -static inline void gen_fop_QDD(DisasContext *dc, int rd, int rs1, int rs2, - void (*gen)(TCGv_ptr, TCGv_i64, TCGv_i64)) -{ - TCGv_i64 src1, src2; - - src1 = gen_load_fpr_D(dc, rs1); - src2 = gen_load_fpr_D(dc, rs2); - - gen(cpu_env, src1, src2); - - gen_op_store_QT0_fpr(QFPREG(rd)); - gen_update_fprs_dirty(QFPREG(rd)); -} - -#ifdef TARGET_SPARC64 -static inline void gen_fop_DF(DisasContext *dc, int rd, int rs, - void (*gen)(TCGv_i64, TCGv_ptr, TCGv_i32)) -{ - TCGv_i64 dst; - TCGv_i32 src; - - src = gen_load_fpr_F(dc, rs); - dst = gen_dest_fpr_D(dc, rd); - - gen(dst, cpu_env, src); - - gen_store_fpr_D(dc, rd, dst); -} -#endif - -static inline void gen_ne_fop_DF(DisasContext *dc, int rd, int rs, - void (*gen)(TCGv_i64, TCGv_ptr, TCGv_i32)) -{ - TCGv_i64 dst; - TCGv_i32 src; - - src = gen_load_fpr_F(dc, rs); - dst = gen_dest_fpr_D(dc, rd); - - gen(dst, cpu_env, src); - - gen_store_fpr_D(dc, rd, dst); -} - -static inline void gen_fop_FD(DisasContext *dc, int rd, int rs, - void (*gen)(TCGv_i32, TCGv_ptr, TCGv_i64)) -{ - TCGv_i32 dst; - TCGv_i64 src; - - src = gen_load_fpr_D(dc, rs); - dst = gen_dest_fpr_F(dc); - - gen(dst, cpu_env, src); - - gen_store_fpr_F(dc, rd, dst); -} - -static inline void gen_fop_FQ(DisasContext *dc, int rd, int rs, - void (*gen)(TCGv_i32, TCGv_ptr)) -{ - TCGv_i32 dst; - - gen_op_load_fpr_QT1(QFPREG(rs)); - dst = gen_dest_fpr_F(dc); - - gen(dst, cpu_env); - - gen_store_fpr_F(dc, rd, dst); -} - -static inline void gen_fop_DQ(DisasContext *dc, int rd, int rs, - void (*gen)(TCGv_i64, TCGv_ptr)) -{ - TCGv_i64 dst; - - gen_op_load_fpr_QT1(QFPREG(rs)); - dst = gen_dest_fpr_D(dc, rd); - - gen(dst, cpu_env); - - gen_store_fpr_D(dc, rd, dst); -} - -static inline void gen_ne_fop_QF(DisasContext *dc, int rd, int rs, - void (*gen)(TCGv_ptr, TCGv_i32)) -{ - TCGv_i32 src; - - src = gen_load_fpr_F(dc, rs); - - gen(cpu_env, src); - - gen_op_store_QT0_fpr(QFPREG(rd)); - gen_update_fprs_dirty(QFPREG(rd)); -} - -static inline void gen_ne_fop_QD(DisasContext *dc, int rd, int rs, - void (*gen)(TCGv_ptr, TCGv_i64)) -{ - TCGv_i64 src; - - src = gen_load_fpr_D(dc, rs); - - gen(cpu_env, src); - - gen_op_store_QT0_fpr(QFPREG(rd)); - gen_update_fprs_dirty(QFPREG(rd)); -} - -/* asi moves */ -#ifdef TARGET_SPARC64 -static inline TCGv_i32 gen_get_asi(int insn, TCGv r_addr) -{ - int asi; - TCGv_i32 r_asi; - - if (IS_IMM) { - r_asi = tcg_temp_new_i32(); - tcg_gen_mov_i32(r_asi, cpu_asi); - } else { - asi = GET_FIELD(insn, 19, 26); - r_asi = tcg_const_i32(asi); - } - return r_asi; -} - -static inline void gen_ld_asi(TCGv dst, TCGv addr, int insn, int size, - int sign) -{ - TCGv_i32 r_asi, r_size, r_sign; - - r_asi = gen_get_asi(insn, addr); - r_size = tcg_const_i32(size); - r_sign = tcg_const_i32(sign); - gen_helper_ld_asi(dst, cpu_env, addr, r_asi, r_size, r_sign); - tcg_temp_free_i32(r_sign); - tcg_temp_free_i32(r_size); - tcg_temp_free_i32(r_asi); -} - -static inline void gen_st_asi(TCGv src, TCGv addr, int insn, int size) -{ - TCGv_i32 r_asi, r_size; - - r_asi = gen_get_asi(insn, addr); - r_size = tcg_const_i32(size); - gen_helper_st_asi(cpu_env, addr, src, r_asi, r_size); - tcg_temp_free_i32(r_size); - tcg_temp_free_i32(r_asi); -} - -static inline void gen_ldf_asi(TCGv addr, int insn, int size, int rd) -{ - TCGv_i32 r_asi, r_size, r_rd; - - r_asi = gen_get_asi(insn, addr); - r_size = tcg_const_i32(size); - r_rd = tcg_const_i32(rd); - gen_helper_ldf_asi(cpu_env, addr, r_asi, r_size, r_rd); - tcg_temp_free_i32(r_rd); - tcg_temp_free_i32(r_size); - tcg_temp_free_i32(r_asi); -} - -static inline void gen_stf_asi(TCGv addr, int insn, int size, int rd) -{ - TCGv_i32 r_asi, r_size, r_rd; - - r_asi = gen_get_asi(insn, addr); - r_size = tcg_const_i32(size); - r_rd = tcg_const_i32(rd); - gen_helper_stf_asi(cpu_env, addr, r_asi, r_size, r_rd); - tcg_temp_free_i32(r_rd); - tcg_temp_free_i32(r_size); - tcg_temp_free_i32(r_asi); -} - -static inline void gen_swap_asi(TCGv dst, TCGv src, TCGv addr, int insn) -{ - TCGv_i32 r_asi, r_size, r_sign; - TCGv_i64 t64 = tcg_temp_new_i64(); - - r_asi = gen_get_asi(insn, addr); - r_size = tcg_const_i32(4); - r_sign = tcg_const_i32(0); - gen_helper_ld_asi(t64, cpu_env, addr, r_asi, r_size, r_sign); - tcg_temp_free_i32(r_sign); - gen_helper_st_asi(cpu_env, addr, src, r_asi, r_size); - tcg_temp_free_i32(r_size); - tcg_temp_free_i32(r_asi); - tcg_gen_trunc_i64_tl(dst, t64); - tcg_temp_free_i64(t64); -} - -static inline void gen_ldda_asi(DisasContext *dc, TCGv hi, TCGv addr, - int insn, int rd) -{ - TCGv_i32 r_asi, r_rd; - - r_asi = gen_get_asi(insn, addr); - r_rd = tcg_const_i32(rd); - gen_helper_ldda_asi(cpu_env, addr, r_asi, r_rd); - tcg_temp_free_i32(r_rd); - tcg_temp_free_i32(r_asi); -} - -static inline void gen_stda_asi(DisasContext *dc, TCGv hi, TCGv addr, - int insn, int rd) -{ - TCGv_i32 r_asi, r_size; - TCGv lo = gen_load_gpr(dc, rd + 1); - TCGv_i64 t64 = tcg_temp_new_i64(); - - tcg_gen_concat_tl_i64(t64, lo, hi); - r_asi = gen_get_asi(insn, addr); - r_size = tcg_const_i32(8); - gen_helper_st_asi(cpu_env, addr, t64, r_asi, r_size); - tcg_temp_free_i32(r_size); - tcg_temp_free_i32(r_asi); - tcg_temp_free_i64(t64); -} - -static inline void gen_casx_asi(DisasContext *dc, TCGv addr, - TCGv val2, int insn, int rd) -{ - TCGv val1 = gen_load_gpr(dc, rd); - TCGv dst = gen_dest_gpr(dc, rd); - TCGv_i32 r_asi = gen_get_asi(insn, addr); - - gen_helper_casx_asi(dst, cpu_env, addr, val1, val2, r_asi); - tcg_temp_free_i32(r_asi); - gen_store_gpr(dc, rd, dst); -} - -#elif !defined(CONFIG_USER_ONLY) - -static inline void gen_ld_asi(TCGv dst, TCGv addr, int insn, int size, - int sign) -{ - TCGv_i32 r_asi, r_size, r_sign; - TCGv_i64 t64 = tcg_temp_new_i64(); - - r_asi = tcg_const_i32(GET_FIELD(insn, 19, 26)); - r_size = tcg_const_i32(size); - r_sign = tcg_const_i32(sign); - gen_helper_ld_asi(t64, cpu_env, addr, r_asi, r_size, r_sign); - tcg_temp_free_i32(r_sign); - tcg_temp_free_i32(r_size); - tcg_temp_free_i32(r_asi); - tcg_gen_trunc_i64_tl(dst, t64); - tcg_temp_free_i64(t64); -} - -static inline void gen_st_asi(TCGv src, TCGv addr, int insn, int size) -{ - TCGv_i32 r_asi, r_size; - TCGv_i64 t64 = tcg_temp_new_i64(); - - tcg_gen_extu_tl_i64(t64, src); - r_asi = tcg_const_i32(GET_FIELD(insn, 19, 26)); - r_size = tcg_const_i32(size); - gen_helper_st_asi(cpu_env, addr, t64, r_asi, r_size); - tcg_temp_free_i32(r_size); - tcg_temp_free_i32(r_asi); - tcg_temp_free_i64(t64); -} - -static inline void gen_swap_asi(TCGv dst, TCGv src, TCGv addr, int insn) -{ - TCGv_i32 r_asi, r_size, r_sign; - TCGv_i64 r_val, t64; - - r_asi = tcg_const_i32(GET_FIELD(insn, 19, 26)); - r_size = tcg_const_i32(4); - r_sign = tcg_const_i32(0); - t64 = tcg_temp_new_i64(); - gen_helper_ld_asi(t64, cpu_env, addr, r_asi, r_size, r_sign); - tcg_temp_free(r_sign); - r_val = tcg_temp_new_i64(); - tcg_gen_extu_tl_i64(r_val, src); - gen_helper_st_asi(cpu_env, addr, r_val, r_asi, r_size); - tcg_temp_free_i64(r_val); - tcg_temp_free_i32(r_size); - tcg_temp_free_i32(r_asi); - tcg_gen_trunc_i64_tl(dst, t64); - tcg_temp_free_i64(t64); -} - -static inline void gen_ldda_asi(DisasContext *dc, TCGv hi, TCGv addr, - int insn, int rd) -{ - TCGv_i32 r_asi, r_size, r_sign; - TCGv t; - TCGv_i64 t64; - - r_asi = tcg_const_i32(GET_FIELD(insn, 19, 26)); - r_size = tcg_const_i32(8); - r_sign = tcg_const_i32(0); - t64 = tcg_temp_new_i64(); - gen_helper_ld_asi(t64, cpu_env, addr, r_asi, r_size, r_sign); - tcg_temp_free_i32(r_sign); - tcg_temp_free_i32(r_size); - tcg_temp_free_i32(r_asi); - - /* ??? Work around an apparent bug in Ubuntu gcc 4.8.2-10ubuntu2+12, - whereby "rd + 1" elicits "error: array subscript is above array". - Since we have already asserted that rd is even, the semantics - are unchanged. */ - t = gen_dest_gpr(dc, rd | 1); - tcg_gen_trunc_i64_tl(t, t64); - gen_store_gpr(dc, rd | 1, t); - - tcg_gen_shri_i64(t64, t64, 32); - tcg_gen_trunc_i64_tl(hi, t64); - tcg_temp_free_i64(t64); - gen_store_gpr(dc, rd, hi); -} - -static inline void gen_stda_asi(DisasContext *dc, TCGv hi, TCGv addr, - int insn, int rd) -{ - TCGv_i32 r_asi, r_size; - TCGv lo = gen_load_gpr(dc, rd + 1); - TCGv_i64 t64 = tcg_temp_new_i64(); - - tcg_gen_concat_tl_i64(t64, lo, hi); - r_asi = tcg_const_i32(GET_FIELD(insn, 19, 26)); - r_size = tcg_const_i32(8); - gen_helper_st_asi(cpu_env, addr, t64, r_asi, r_size); - tcg_temp_free_i32(r_size); - tcg_temp_free_i32(r_asi); - tcg_temp_free_i64(t64); -} -#endif - -#if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64) -static inline void gen_cas_asi(DisasContext *dc, TCGv addr, - TCGv val2, int insn, int rd) -{ - TCGv val1 = gen_load_gpr(dc, rd); - TCGv dst = gen_dest_gpr(dc, rd); -#ifdef TARGET_SPARC64 - TCGv_i32 r_asi = gen_get_asi(insn, addr); -#else - TCGv_i32 r_asi = tcg_const_i32(GET_FIELD(insn, 19, 26)); -#endif - - gen_helper_cas_asi(dst, cpu_env, addr, val1, val2, r_asi); - tcg_temp_free_i32(r_asi); - gen_store_gpr(dc, rd, dst); -} - -static inline void gen_ldstub_asi(TCGv dst, TCGv addr, int insn) -{ - TCGv_i64 r_val; - TCGv_i32 r_asi, r_size; - - gen_ld_asi(dst, addr, insn, 1, 0); - - r_val = tcg_const_i64(0xffULL); - r_asi = tcg_const_i32(GET_FIELD(insn, 19, 26)); - r_size = tcg_const_i32(1); - gen_helper_st_asi(cpu_env, addr, r_val, r_asi, r_size); - tcg_temp_free_i32(r_size); - tcg_temp_free_i32(r_asi); - tcg_temp_free_i64(r_val); -} -#endif - -static TCGv get_src1(DisasContext *dc, unsigned int insn) -{ - unsigned int rs1 = GET_FIELD(insn, 13, 17); - return gen_load_gpr(dc, rs1); -} - -static TCGv get_src2(DisasContext *dc, unsigned int insn) -{ - if (IS_IMM) { /* immediate */ - target_long simm = GET_FIELDs(insn, 19, 31); - TCGv t = get_temp_tl(dc); - tcg_gen_movi_tl(t, simm); - return t; - } else { /* register */ - unsigned int rs2 = GET_FIELD(insn, 27, 31); - return gen_load_gpr(dc, rs2); - } -} - -#ifdef TARGET_SPARC64 -static void gen_fmovs(DisasContext *dc, DisasCompare *cmp, int rd, int rs) -{ - TCGv_i32 c32, zero, dst, s1, s2; - - /* We have two choices here: extend the 32 bit data and use movcond_i64, - or fold the comparison down to 32 bits and use movcond_i32. Choose - the later. */ - c32 = tcg_temp_new_i32(); - if (cmp->is_bool) { - tcg_gen_extrl_i64_i32(c32, cmp->c1); - } else { - TCGv_i64 c64 = tcg_temp_new_i64(); - tcg_gen_setcond_i64(cmp->cond, c64, cmp->c1, cmp->c2); - tcg_gen_extrl_i64_i32(c32, c64); - tcg_temp_free_i64(c64); - } - - s1 = gen_load_fpr_F(dc, rs); - s2 = gen_load_fpr_F(dc, rd); - dst = gen_dest_fpr_F(dc); - zero = tcg_const_i32(0); - - tcg_gen_movcond_i32(TCG_COND_NE, dst, c32, zero, s1, s2); - - tcg_temp_free_i32(c32); - tcg_temp_free_i32(zero); - gen_store_fpr_F(dc, rd, dst); -} - -static void gen_fmovd(DisasContext *dc, DisasCompare *cmp, int rd, int rs) -{ - TCGv_i64 dst = gen_dest_fpr_D(dc, rd); - tcg_gen_movcond_i64(cmp->cond, dst, cmp->c1, cmp->c2, - gen_load_fpr_D(dc, rs), - gen_load_fpr_D(dc, rd)); - gen_store_fpr_D(dc, rd, dst); -} - -static void gen_fmovq(DisasContext *dc, DisasCompare *cmp, int rd, int rs) -{ - int qd = QFPREG(rd); - int qs = QFPREG(rs); - - tcg_gen_movcond_i64(cmp->cond, cpu_fpr[qd / 2], cmp->c1, cmp->c2, - cpu_fpr[qs / 2], cpu_fpr[qd / 2]); - tcg_gen_movcond_i64(cmp->cond, cpu_fpr[qd / 2 + 1], cmp->c1, cmp->c2, - cpu_fpr[qs / 2 + 1], cpu_fpr[qd / 2 + 1]); - - gen_update_fprs_dirty(qd); -} - -#ifndef CONFIG_USER_ONLY -static inline void gen_load_trap_state_at_tl(TCGv_ptr r_tsptr, TCGv_env cpu_env) -{ - TCGv_i32 r_tl = tcg_temp_new_i32(); - - /* load env->tl into r_tl */ - tcg_gen_ld_i32(r_tl, cpu_env, offsetof(CPUSPARCState, tl)); - - /* tl = [0 ... MAXTL_MASK] where MAXTL_MASK must be power of 2 */ - tcg_gen_andi_i32(r_tl, r_tl, MAXTL_MASK); - - /* calculate offset to current trap state from env->ts, reuse r_tl */ - tcg_gen_muli_i32(r_tl, r_tl, sizeof (trap_state)); - tcg_gen_addi_ptr(r_tsptr, cpu_env, offsetof(CPUSPARCState, ts)); - - /* tsptr = env->ts[env->tl & MAXTL_MASK] */ - { - TCGv_ptr r_tl_tmp = tcg_temp_new_ptr(); - tcg_gen_ext_i32_ptr(r_tl_tmp, r_tl); - tcg_gen_add_ptr(r_tsptr, r_tsptr, r_tl_tmp); - tcg_temp_free_ptr(r_tl_tmp); - } - - tcg_temp_free_i32(r_tl); -} -#endif - -static void gen_edge(DisasContext *dc, TCGv dst, TCGv s1, TCGv s2, - int width, bool cc, bool left) -{ - TCGv lo1, lo2, t1, t2; - uint64_t amask, tabl, tabr; - int shift, imask, omask; - - if (cc) { - tcg_gen_mov_tl(cpu_cc_src, s1); - tcg_gen_mov_tl(cpu_cc_src2, s2); - tcg_gen_sub_tl(cpu_cc_dst, s1, s2); - tcg_gen_movi_i32(cpu_cc_op, CC_OP_SUB); - dc->cc_op = CC_OP_SUB; - } - - /* Theory of operation: there are two tables, left and right (not to - be confused with the left and right versions of the opcode). These - are indexed by the low 3 bits of the inputs. To make things "easy", - these tables are loaded into two constants, TABL and TABR below. - The operation index = (input & imask) << shift calculates the index - into the constant, while val = (table >> index) & omask calculates - the value we're looking for. */ - switch (width) { - case 8: - imask = 0x7; - shift = 3; - omask = 0xff; - if (left) { - tabl = 0x80c0e0f0f8fcfeffULL; - tabr = 0xff7f3f1f0f070301ULL; - } else { - tabl = 0x0103070f1f3f7fffULL; - tabr = 0xfffefcf8f0e0c080ULL; - } - break; - case 16: - imask = 0x6; - shift = 1; - omask = 0xf; - if (left) { - tabl = 0x8cef; - tabr = 0xf731; - } else { - tabl = 0x137f; - tabr = 0xfec8; - } - break; - case 32: - imask = 0x4; - shift = 0; - omask = 0x3; - if (left) { - tabl = (2 << 2) | 3; - tabr = (3 << 2) | 1; - } else { - tabl = (1 << 2) | 3; - tabr = (3 << 2) | 2; - } - break; - default: - abort(); - } - - lo1 = tcg_temp_new(); - lo2 = tcg_temp_new(); - tcg_gen_andi_tl(lo1, s1, imask); - tcg_gen_andi_tl(lo2, s2, imask); - tcg_gen_shli_tl(lo1, lo1, shift); - tcg_gen_shli_tl(lo2, lo2, shift); - - t1 = tcg_const_tl(tabl); - t2 = tcg_const_tl(tabr); - tcg_gen_shr_tl(lo1, t1, lo1); - tcg_gen_shr_tl(lo2, t2, lo2); - tcg_gen_andi_tl(dst, lo1, omask); - tcg_gen_andi_tl(lo2, lo2, omask); - - amask = -8; - if (AM_CHECK(dc)) { - amask &= 0xffffffffULL; - } - tcg_gen_andi_tl(s1, s1, amask); - tcg_gen_andi_tl(s2, s2, amask); - - /* We want to compute - dst = (s1 == s2 ? lo1 : lo1 & lo2). - We've already done dst = lo1, so this reduces to - dst &= (s1 == s2 ? -1 : lo2) - Which we perform by - lo2 |= -(s1 == s2) - dst &= lo2 - */ - tcg_gen_setcond_tl(TCG_COND_EQ, t1, s1, s2); - tcg_gen_neg_tl(t1, t1); - tcg_gen_or_tl(lo2, lo2, t1); - tcg_gen_and_tl(dst, dst, lo2); - - tcg_temp_free(lo1); - tcg_temp_free(lo2); - tcg_temp_free(t1); - tcg_temp_free(t2); -} - -static void gen_alignaddr(TCGv dst, TCGv s1, TCGv s2, bool left) -{ - TCGv tmp = tcg_temp_new(); - - tcg_gen_add_tl(tmp, s1, s2); - tcg_gen_andi_tl(dst, tmp, -8); - if (left) { - tcg_gen_neg_tl(tmp, tmp); - } - tcg_gen_deposit_tl(cpu_gsr, cpu_gsr, tmp, 0, 3); - - tcg_temp_free(tmp); -} - -static void gen_faligndata(TCGv dst, TCGv gsr, TCGv s1, TCGv s2) -{ - TCGv t1, t2, shift; - - t1 = tcg_temp_new(); - t2 = tcg_temp_new(); - shift = tcg_temp_new(); - - tcg_gen_andi_tl(shift, gsr, 7); - tcg_gen_shli_tl(shift, shift, 3); - tcg_gen_shl_tl(t1, s1, shift); - - /* A shift of 64 does not produce 0 in TCG. Divide this into a - shift of (up to 63) followed by a constant shift of 1. */ - tcg_gen_xori_tl(shift, shift, 63); - tcg_gen_shr_tl(t2, s2, shift); - tcg_gen_shri_tl(t2, t2, 1); - - tcg_gen_or_tl(dst, t1, t2); - - tcg_temp_free(t1); - tcg_temp_free(t2); - tcg_temp_free(shift); -} -#endif - -#define CHECK_IU_FEATURE(dc, FEATURE) \ - if (!((dc)->def->features & CPU_FEATURE_ ## FEATURE)) \ - goto illegal_insn; -#define CHECK_FPU_FEATURE(dc, FEATURE) \ - if (!((dc)->def->features & CPU_FEATURE_ ## FEATURE)) \ - goto nfpu_insn; - -/* before an instruction, dc->pc must be static */ -static void disas_sparc_insn(DisasContext * dc, unsigned int insn) -{ - unsigned int opc, rs1, rs2, rd; - TCGv cpu_src1, cpu_src2; - TCGv_i32 cpu_src1_32, cpu_src2_32, cpu_dst_32; - TCGv_i64 cpu_src1_64, cpu_src2_64, cpu_dst_64; - target_long simm; - - opc = GET_FIELD(insn, 0, 1); - rd = GET_FIELD(insn, 2, 6); - - switch (opc) { - case 0: /* branches/sethi */ - { - unsigned int xop = GET_FIELD(insn, 7, 9); - int32_t target; - switch (xop) { -#ifdef TARGET_SPARC64 - case 0x1: /* V9 BPcc */ - { - int cc; - - target = GET_FIELD_SP(insn, 0, 18); - target = sign_extend(target, 19); - target <<= 2; - cc = GET_FIELD_SP(insn, 20, 21); - if (cc == 0) - do_branch(dc, target, insn, 0); - else if (cc == 2) - do_branch(dc, target, insn, 1); - else - goto illegal_insn; - goto jmp_insn; - } - case 0x3: /* V9 BPr */ - { - target = GET_FIELD_SP(insn, 0, 13) | - (GET_FIELD_SP(insn, 20, 21) << 14); - target = sign_extend(target, 16); - target <<= 2; - cpu_src1 = get_src1(dc, insn); - do_branch_reg(dc, target, insn, cpu_src1); - goto jmp_insn; - } - case 0x5: /* V9 FBPcc */ - { - int cc = GET_FIELD_SP(insn, 20, 21); - if (gen_trap_ifnofpu(dc)) { - goto jmp_insn; - } - target = GET_FIELD_SP(insn, 0, 18); - target = sign_extend(target, 19); - target <<= 2; - do_fbranch(dc, target, insn, cc); - goto jmp_insn; - } -#else - case 0x7: /* CBN+x */ - { - goto ncp_insn; - } -#endif - case 0x2: /* BN+x */ - { - target = GET_FIELD(insn, 10, 31); - target = sign_extend(target, 22); - target <<= 2; - do_branch(dc, target, insn, 0); - goto jmp_insn; - } - case 0x6: /* FBN+x */ - { - if (gen_trap_ifnofpu(dc)) { - goto jmp_insn; - } - target = GET_FIELD(insn, 10, 31); - target = sign_extend(target, 22); - target <<= 2; - do_fbranch(dc, target, insn, 0); - goto jmp_insn; - } - case 0x4: /* SETHI */ - /* Special-case %g0 because that's the canonical nop. */ - if (rd) { - uint32_t value = GET_FIELD(insn, 10, 31); - TCGv t = gen_dest_gpr(dc, rd); - tcg_gen_movi_tl(t, value << 10); - gen_store_gpr(dc, rd, t); - } - break; - case 0x0: /* UNIMPL */ - default: - goto illegal_insn; - } - break; - } - break; - case 1: /*CALL*/ - { - target_long target = GET_FIELDs(insn, 2, 31) << 2; - TCGv o7 = gen_dest_gpr(dc, 15); - - tcg_gen_movi_tl(o7, dc->pc); - gen_store_gpr(dc, 15, o7); - target += dc->pc; - gen_mov_pc_npc(dc); -#ifdef TARGET_SPARC64 - if (unlikely(AM_CHECK(dc))) { - target &= 0xffffffffULL; - } -#endif - dc->npc = target; - } - goto jmp_insn; - case 2: /* FPU & Logical Operations */ - { - unsigned int xop = GET_FIELD(insn, 7, 12); - TCGv cpu_dst = get_temp_tl(dc); - TCGv cpu_tmp0; - - if (xop == 0x3a) { /* generate trap */ - int cond = GET_FIELD(insn, 3, 6); - TCGv_i32 trap; - TCGLabel *l1 = NULL; - int mask; - - if (cond == 0) { - /* Trap never. */ - break; - } - - save_state(dc); - - if (cond != 8) { - /* Conditional trap. */ - DisasCompare cmp; -#ifdef TARGET_SPARC64 - /* V9 icc/xcc */ - int cc = GET_FIELD_SP(insn, 11, 12); - if (cc == 0) { - gen_compare(&cmp, 0, cond, dc); - } else if (cc == 2) { - gen_compare(&cmp, 1, cond, dc); - } else { - goto illegal_insn; - } -#else - gen_compare(&cmp, 0, cond, dc); -#endif - l1 = gen_new_label(); - tcg_gen_brcond_tl(tcg_invert_cond(cmp.cond), - cmp.c1, cmp.c2, l1); - free_compare(&cmp); - } - - mask = ((dc->def->features & CPU_FEATURE_HYPV) && supervisor(dc) - ? UA2005_HTRAP_MASK : V8_TRAP_MASK); - - /* Don't use the normal temporaries, as they may well have - gone out of scope with the branch above. While we're - doing that we might as well pre-truncate to 32-bit. */ - trap = tcg_temp_new_i32(); - - rs1 = GET_FIELD_SP(insn, 14, 18); - if (IS_IMM) { - rs2 = GET_FIELD_SP(insn, 0, 6); - if (rs1 == 0) { - tcg_gen_movi_i32(trap, (rs2 & mask) + TT_TRAP); - /* Signal that the trap value is fully constant. */ - mask = 0; - } else { - TCGv t1 = gen_load_gpr(dc, rs1); - tcg_gen_trunc_tl_i32(trap, t1); - tcg_gen_addi_i32(trap, trap, rs2); - } - } else { - TCGv t1, t2; - rs2 = GET_FIELD_SP(insn, 0, 4); - t1 = gen_load_gpr(dc, rs1); - t2 = gen_load_gpr(dc, rs2); - tcg_gen_add_tl(t1, t1, t2); - tcg_gen_trunc_tl_i32(trap, t1); - } - if (mask != 0) { - tcg_gen_andi_i32(trap, trap, mask); - tcg_gen_addi_i32(trap, trap, TT_TRAP); - } - - gen_helper_raise_exception(cpu_env, trap); - tcg_temp_free_i32(trap); - - if (cond == 8) { - /* An unconditional trap ends the TB. */ - dc->is_br = 1; - goto jmp_insn; - } else { - /* A conditional trap falls through to the next insn. */ - gen_set_label(l1); - break; - } - } else if (xop == 0x28) { - rs1 = GET_FIELD(insn, 13, 17); - switch(rs1) { - case 0: /* rdy */ -#ifndef TARGET_SPARC64 - case 0x01 ... 0x0e: /* undefined in the SPARCv8 - manual, rdy on the microSPARC - II */ - case 0x0f: /* stbar in the SPARCv8 manual, - rdy on the microSPARC II */ - case 0x10 ... 0x1f: /* implementation-dependent in the - SPARCv8 manual, rdy on the - microSPARC II */ - /* Read Asr17 */ - if (rs1 == 0x11 && dc->def->features & CPU_FEATURE_ASR17) { - TCGv t = gen_dest_gpr(dc, rd); - /* Read Asr17 for a Leon3 monoprocessor */ - tcg_gen_movi_tl(t, (1 << 8) | (dc->def->nwindows - 1)); - gen_store_gpr(dc, rd, t); - break; - } -#endif - gen_store_gpr(dc, rd, cpu_y); - break; -#ifdef TARGET_SPARC64 - case 0x2: /* V9 rdccr */ - update_psr(dc); - gen_helper_rdccr(cpu_dst, cpu_env); - gen_store_gpr(dc, rd, cpu_dst); - break; - case 0x3: /* V9 rdasi */ - tcg_gen_ext_i32_tl(cpu_dst, cpu_asi); - gen_store_gpr(dc, rd, cpu_dst); - break; - case 0x4: /* V9 rdtick */ - { - TCGv_ptr r_tickptr; - TCGv_i32 r_const; - - r_tickptr = tcg_temp_new_ptr(); - r_const = tcg_const_i32(dc->mem_idx); - tcg_gen_ld_ptr(r_tickptr, cpu_env, - offsetof(CPUSPARCState, tick)); - gen_helper_tick_get_count(cpu_dst, cpu_env, r_tickptr, - r_const); - tcg_temp_free_ptr(r_tickptr); - tcg_temp_free_i32(r_const); - gen_store_gpr(dc, rd, cpu_dst); - } - break; - case 0x5: /* V9 rdpc */ - { - TCGv t = gen_dest_gpr(dc, rd); - if (unlikely(AM_CHECK(dc))) { - tcg_gen_movi_tl(t, dc->pc & 0xffffffffULL); - } else { - tcg_gen_movi_tl(t, dc->pc); - } - gen_store_gpr(dc, rd, t); - } - break; - case 0x6: /* V9 rdfprs */ - tcg_gen_ext_i32_tl(cpu_dst, cpu_fprs); - gen_store_gpr(dc, rd, cpu_dst); - break; - case 0xf: /* V9 membar */ - break; /* no effect */ - case 0x13: /* Graphics Status */ - if (gen_trap_ifnofpu(dc)) { - goto jmp_insn; - } - gen_store_gpr(dc, rd, cpu_gsr); - break; - case 0x16: /* Softint */ - tcg_gen_ext_i32_tl(cpu_dst, cpu_softint); - gen_store_gpr(dc, rd, cpu_dst); - break; - case 0x17: /* Tick compare */ - gen_store_gpr(dc, rd, cpu_tick_cmpr); - break; - case 0x18: /* System tick */ - { - TCGv_ptr r_tickptr; - TCGv_i32 r_const; - - r_tickptr = tcg_temp_new_ptr(); - r_const = tcg_const_i32(dc->mem_idx); - tcg_gen_ld_ptr(r_tickptr, cpu_env, - offsetof(CPUSPARCState, stick)); - gen_helper_tick_get_count(cpu_dst, cpu_env, r_tickptr, - r_const); - tcg_temp_free_ptr(r_tickptr); - tcg_temp_free_i32(r_const); - gen_store_gpr(dc, rd, cpu_dst); - } - break; - case 0x19: /* System tick compare */ - gen_store_gpr(dc, rd, cpu_stick_cmpr); - break; - case 0x10: /* Performance Control */ - case 0x11: /* Performance Instrumentation Counter */ - case 0x12: /* Dispatch Control */ - case 0x14: /* Softint set, WO */ - case 0x15: /* Softint clear, WO */ -#endif - default: - goto illegal_insn; - } -#if !defined(CONFIG_USER_ONLY) - } else if (xop == 0x29) { /* rdpsr / UA2005 rdhpr */ -#ifndef TARGET_SPARC64 - if (!supervisor(dc)) { - goto priv_insn; - } - update_psr(dc); - gen_helper_rdpsr(cpu_dst, cpu_env); -#else - CHECK_IU_FEATURE(dc, HYPV); - if (!hypervisor(dc)) - goto priv_insn; - rs1 = GET_FIELD(insn, 13, 17); - switch (rs1) { - case 0: // hpstate - // gen_op_rdhpstate(); - break; - case 1: // htstate - // gen_op_rdhtstate(); - break; - case 3: // hintp - tcg_gen_mov_tl(cpu_dst, cpu_hintp); - break; - case 5: // htba - tcg_gen_mov_tl(cpu_dst, cpu_htba); - break; - case 6: // hver - tcg_gen_mov_tl(cpu_dst, cpu_hver); - break; - case 31: // hstick_cmpr - tcg_gen_mov_tl(cpu_dst, cpu_hstick_cmpr); - break; - default: - goto illegal_insn; - } -#endif - gen_store_gpr(dc, rd, cpu_dst); - break; - } else if (xop == 0x2a) { /* rdwim / V9 rdpr */ - if (!supervisor(dc)) { - goto priv_insn; - } - cpu_tmp0 = get_temp_tl(dc); -#ifdef TARGET_SPARC64 - rs1 = GET_FIELD(insn, 13, 17); - switch (rs1) { - case 0: // tpc - { - TCGv_ptr r_tsptr; - - r_tsptr = tcg_temp_new_ptr(); - gen_load_trap_state_at_tl(r_tsptr, cpu_env); - tcg_gen_ld_tl(cpu_tmp0, r_tsptr, - offsetof(trap_state, tpc)); - tcg_temp_free_ptr(r_tsptr); - } - break; - case 1: // tnpc - { - TCGv_ptr r_tsptr; - - r_tsptr = tcg_temp_new_ptr(); - gen_load_trap_state_at_tl(r_tsptr, cpu_env); - tcg_gen_ld_tl(cpu_tmp0, r_tsptr, - offsetof(trap_state, tnpc)); - tcg_temp_free_ptr(r_tsptr); - } - break; - case 2: // tstate - { - TCGv_ptr r_tsptr; - - r_tsptr = tcg_temp_new_ptr(); - gen_load_trap_state_at_tl(r_tsptr, cpu_env); - tcg_gen_ld_tl(cpu_tmp0, r_tsptr, - offsetof(trap_state, tstate)); - tcg_temp_free_ptr(r_tsptr); - } - break; - case 3: // tt - { - TCGv_ptr r_tsptr = tcg_temp_new_ptr(); - - gen_load_trap_state_at_tl(r_tsptr, cpu_env); - tcg_gen_ld32s_tl(cpu_tmp0, r_tsptr, - offsetof(trap_state, tt)); - tcg_temp_free_ptr(r_tsptr); - } - break; - case 4: // tick - { - TCGv_ptr r_tickptr; - TCGv_i32 r_const; - - r_tickptr = tcg_temp_new_ptr(); - r_const = tcg_const_i32(dc->mem_idx); - tcg_gen_ld_ptr(r_tickptr, cpu_env, - offsetof(CPUSPARCState, tick)); - gen_helper_tick_get_count(cpu_tmp0, cpu_env, - r_tickptr, r_const); - tcg_temp_free_ptr(r_tickptr); - tcg_temp_free_i32(r_const); - } - break; - case 5: // tba - tcg_gen_mov_tl(cpu_tmp0, cpu_tbr); - break; - case 6: // pstate - tcg_gen_ld32s_tl(cpu_tmp0, cpu_env, - offsetof(CPUSPARCState, pstate)); - break; - case 7: // tl - tcg_gen_ld32s_tl(cpu_tmp0, cpu_env, - offsetof(CPUSPARCState, tl)); - break; - case 8: // pil - tcg_gen_ld32s_tl(cpu_tmp0, cpu_env, - offsetof(CPUSPARCState, psrpil)); - break; - case 9: // cwp - gen_helper_rdcwp(cpu_tmp0, cpu_env); - break; - case 10: // cansave - tcg_gen_ld32s_tl(cpu_tmp0, cpu_env, - offsetof(CPUSPARCState, cansave)); - break; - case 11: // canrestore - tcg_gen_ld32s_tl(cpu_tmp0, cpu_env, - offsetof(CPUSPARCState, canrestore)); - break; - case 12: // cleanwin - tcg_gen_ld32s_tl(cpu_tmp0, cpu_env, - offsetof(CPUSPARCState, cleanwin)); - break; - case 13: // otherwin - tcg_gen_ld32s_tl(cpu_tmp0, cpu_env, - offsetof(CPUSPARCState, otherwin)); - break; - case 14: // wstate - tcg_gen_ld32s_tl(cpu_tmp0, cpu_env, - offsetof(CPUSPARCState, wstate)); - break; - case 16: // UA2005 gl - CHECK_IU_FEATURE(dc, GL); - tcg_gen_ld32s_tl(cpu_tmp0, cpu_env, - offsetof(CPUSPARCState, gl)); - break; - case 26: // UA2005 strand status - CHECK_IU_FEATURE(dc, HYPV); - if (!hypervisor(dc)) - goto priv_insn; - tcg_gen_mov_tl(cpu_tmp0, cpu_ssr); - break; - case 31: // ver - tcg_gen_mov_tl(cpu_tmp0, cpu_ver); - break; - case 15: // fq - default: - goto illegal_insn; - } -#else - tcg_gen_ext_i32_tl(cpu_tmp0, cpu_wim); -#endif - gen_store_gpr(dc, rd, cpu_tmp0); - break; - } else if (xop == 0x2b) { /* rdtbr / V9 flushw */ -#ifdef TARGET_SPARC64 - save_state(dc); - gen_helper_flushw(cpu_env); -#else - if (!supervisor(dc)) - goto priv_insn; - gen_store_gpr(dc, rd, cpu_tbr); -#endif - break; -#endif - } else if (xop == 0x34) { /* FPU Operations */ - if (gen_trap_ifnofpu(dc)) { - goto jmp_insn; - } - gen_op_clear_ieee_excp_and_FTT(); - rs1 = GET_FIELD(insn, 13, 17); - rs2 = GET_FIELD(insn, 27, 31); - xop = GET_FIELD(insn, 18, 26); - save_state(dc); - switch (xop) { - case 0x1: /* fmovs */ - cpu_src1_32 = gen_load_fpr_F(dc, rs2); - gen_store_fpr_F(dc, rd, cpu_src1_32); - break; - case 0x5: /* fnegs */ - gen_ne_fop_FF(dc, rd, rs2, gen_helper_fnegs); - break; - case 0x9: /* fabss */ - gen_ne_fop_FF(dc, rd, rs2, gen_helper_fabss); - break; - case 0x29: /* fsqrts */ - CHECK_FPU_FEATURE(dc, FSQRT); - gen_fop_FF(dc, rd, rs2, gen_helper_fsqrts); - break; - case 0x2a: /* fsqrtd */ - CHECK_FPU_FEATURE(dc, FSQRT); - gen_fop_DD(dc, rd, rs2, gen_helper_fsqrtd); - break; - case 0x2b: /* fsqrtq */ - CHECK_FPU_FEATURE(dc, FLOAT128); - gen_fop_QQ(dc, rd, rs2, gen_helper_fsqrtq); - break; - case 0x41: /* fadds */ - gen_fop_FFF(dc, rd, rs1, rs2, gen_helper_fadds); - break; - case 0x42: /* faddd */ - gen_fop_DDD(dc, rd, rs1, rs2, gen_helper_faddd); - break; - case 0x43: /* faddq */ - CHECK_FPU_FEATURE(dc, FLOAT128); - gen_fop_QQQ(dc, rd, rs1, rs2, gen_helper_faddq); - break; - case 0x45: /* fsubs */ - gen_fop_FFF(dc, rd, rs1, rs2, gen_helper_fsubs); - break; - case 0x46: /* fsubd */ - gen_fop_DDD(dc, rd, rs1, rs2, gen_helper_fsubd); - break; - case 0x47: /* fsubq */ - CHECK_FPU_FEATURE(dc, FLOAT128); - gen_fop_QQQ(dc, rd, rs1, rs2, gen_helper_fsubq); - break; - case 0x49: /* fmuls */ - CHECK_FPU_FEATURE(dc, FMUL); - gen_fop_FFF(dc, rd, rs1, rs2, gen_helper_fmuls); - break; - case 0x4a: /* fmuld */ - CHECK_FPU_FEATURE(dc, FMUL); - gen_fop_DDD(dc, rd, rs1, rs2, gen_helper_fmuld); - break; - case 0x4b: /* fmulq */ - CHECK_FPU_FEATURE(dc, FLOAT128); - CHECK_FPU_FEATURE(dc, FMUL); - gen_fop_QQQ(dc, rd, rs1, rs2, gen_helper_fmulq); - break; - case 0x4d: /* fdivs */ - gen_fop_FFF(dc, rd, rs1, rs2, gen_helper_fdivs); - break; - case 0x4e: /* fdivd */ - gen_fop_DDD(dc, rd, rs1, rs2, gen_helper_fdivd); - break; - case 0x4f: /* fdivq */ - CHECK_FPU_FEATURE(dc, FLOAT128); - gen_fop_QQQ(dc, rd, rs1, rs2, gen_helper_fdivq); - break; - case 0x69: /* fsmuld */ - CHECK_FPU_FEATURE(dc, FSMULD); - gen_fop_DFF(dc, rd, rs1, rs2, gen_helper_fsmuld); - break; - case 0x6e: /* fdmulq */ - CHECK_FPU_FEATURE(dc, FLOAT128); - gen_fop_QDD(dc, rd, rs1, rs2, gen_helper_fdmulq); - break; - case 0xc4: /* fitos */ - gen_fop_FF(dc, rd, rs2, gen_helper_fitos); - break; - case 0xc6: /* fdtos */ - gen_fop_FD(dc, rd, rs2, gen_helper_fdtos); - break; - case 0xc7: /* fqtos */ - CHECK_FPU_FEATURE(dc, FLOAT128); - gen_fop_FQ(dc, rd, rs2, gen_helper_fqtos); - break; - case 0xc8: /* fitod */ - gen_ne_fop_DF(dc, rd, rs2, gen_helper_fitod); - break; - case 0xc9: /* fstod */ - gen_ne_fop_DF(dc, rd, rs2, gen_helper_fstod); - break; - case 0xcb: /* fqtod */ - CHECK_FPU_FEATURE(dc, FLOAT128); - gen_fop_DQ(dc, rd, rs2, gen_helper_fqtod); - break; - case 0xcc: /* fitoq */ - CHECK_FPU_FEATURE(dc, FLOAT128); - gen_ne_fop_QF(dc, rd, rs2, gen_helper_fitoq); - break; - case 0xcd: /* fstoq */ - CHECK_FPU_FEATURE(dc, FLOAT128); - gen_ne_fop_QF(dc, rd, rs2, gen_helper_fstoq); - break; - case 0xce: /* fdtoq */ - CHECK_FPU_FEATURE(dc, FLOAT128); - gen_ne_fop_QD(dc, rd, rs2, gen_helper_fdtoq); - break; - case 0xd1: /* fstoi */ - gen_fop_FF(dc, rd, rs2, gen_helper_fstoi); - break; - case 0xd2: /* fdtoi */ - gen_fop_FD(dc, rd, rs2, gen_helper_fdtoi); - break; - case 0xd3: /* fqtoi */ - CHECK_FPU_FEATURE(dc, FLOAT128); - gen_fop_FQ(dc, rd, rs2, gen_helper_fqtoi); - break; -#ifdef TARGET_SPARC64 - case 0x2: /* V9 fmovd */ - cpu_src1_64 = gen_load_fpr_D(dc, rs2); - gen_store_fpr_D(dc, rd, cpu_src1_64); - break; - case 0x3: /* V9 fmovq */ - CHECK_FPU_FEATURE(dc, FLOAT128); - gen_move_Q(rd, rs2); - break; - case 0x6: /* V9 fnegd */ - gen_ne_fop_DD(dc, rd, rs2, gen_helper_fnegd); - break; - case 0x7: /* V9 fnegq */ - CHECK_FPU_FEATURE(dc, FLOAT128); - gen_ne_fop_QQ(dc, rd, rs2, gen_helper_fnegq); - break; - case 0xa: /* V9 fabsd */ - gen_ne_fop_DD(dc, rd, rs2, gen_helper_fabsd); - break; - case 0xb: /* V9 fabsq */ - CHECK_FPU_FEATURE(dc, FLOAT128); - gen_ne_fop_QQ(dc, rd, rs2, gen_helper_fabsq); - break; - case 0x81: /* V9 fstox */ - gen_fop_DF(dc, rd, rs2, gen_helper_fstox); - break; - case 0x82: /* V9 fdtox */ - gen_fop_DD(dc, rd, rs2, gen_helper_fdtox); - break; - case 0x83: /* V9 fqtox */ - CHECK_FPU_FEATURE(dc, FLOAT128); - gen_fop_DQ(dc, rd, rs2, gen_helper_fqtox); - break; - case 0x84: /* V9 fxtos */ - gen_fop_FD(dc, rd, rs2, gen_helper_fxtos); - break; - case 0x88: /* V9 fxtod */ - gen_fop_DD(dc, rd, rs2, gen_helper_fxtod); - break; - case 0x8c: /* V9 fxtoq */ - CHECK_FPU_FEATURE(dc, FLOAT128); - gen_ne_fop_QD(dc, rd, rs2, gen_helper_fxtoq); - break; -#endif - default: - goto illegal_insn; - } - } else if (xop == 0x35) { /* FPU Operations */ -#ifdef TARGET_SPARC64 - int cond; -#endif - if (gen_trap_ifnofpu(dc)) { - goto jmp_insn; - } - gen_op_clear_ieee_excp_and_FTT(); - rs1 = GET_FIELD(insn, 13, 17); - rs2 = GET_FIELD(insn, 27, 31); - xop = GET_FIELD(insn, 18, 26); - save_state(dc); - -#ifdef TARGET_SPARC64 -#define FMOVR(sz) \ - do { \ - DisasCompare cmp; \ - cond = GET_FIELD_SP(insn, 10, 12); \ - cpu_src1 = get_src1(dc, insn); \ - gen_compare_reg(&cmp, cond, cpu_src1); \ - gen_fmov##sz(dc, &cmp, rd, rs2); \ - free_compare(&cmp); \ - } while (0) - - if ((xop & 0x11f) == 0x005) { /* V9 fmovsr */ - FMOVR(s); - break; - } else if ((xop & 0x11f) == 0x006) { // V9 fmovdr - FMOVR(d); - break; - } else if ((xop & 0x11f) == 0x007) { // V9 fmovqr - CHECK_FPU_FEATURE(dc, FLOAT128); - FMOVR(q); - break; - } -#undef FMOVR -#endif - switch (xop) { -#ifdef TARGET_SPARC64 -#define FMOVCC(fcc, sz) \ - do { \ - DisasCompare cmp; \ - cond = GET_FIELD_SP(insn, 14, 17); \ - gen_fcompare(&cmp, fcc, cond); \ - gen_fmov##sz(dc, &cmp, rd, rs2); \ - free_compare(&cmp); \ - } while (0) - - case 0x001: /* V9 fmovscc %fcc0 */ - FMOVCC(0, s); - break; - case 0x002: /* V9 fmovdcc %fcc0 */ - FMOVCC(0, d); - break; - case 0x003: /* V9 fmovqcc %fcc0 */ - CHECK_FPU_FEATURE(dc, FLOAT128); - FMOVCC(0, q); - break; - case 0x041: /* V9 fmovscc %fcc1 */ - FMOVCC(1, s); - break; - case 0x042: /* V9 fmovdcc %fcc1 */ - FMOVCC(1, d); - break; - case 0x043: /* V9 fmovqcc %fcc1 */ - CHECK_FPU_FEATURE(dc, FLOAT128); - FMOVCC(1, q); - break; - case 0x081: /* V9 fmovscc %fcc2 */ - FMOVCC(2, s); - break; - case 0x082: /* V9 fmovdcc %fcc2 */ - FMOVCC(2, d); - break; - case 0x083: /* V9 fmovqcc %fcc2 */ - CHECK_FPU_FEATURE(dc, FLOAT128); - FMOVCC(2, q); - break; - case 0x0c1: /* V9 fmovscc %fcc3 */ - FMOVCC(3, s); - break; - case 0x0c2: /* V9 fmovdcc %fcc3 */ - FMOVCC(3, d); - break; - case 0x0c3: /* V9 fmovqcc %fcc3 */ - CHECK_FPU_FEATURE(dc, FLOAT128); - FMOVCC(3, q); - break; -#undef FMOVCC -#define FMOVCC(xcc, sz) \ - do { \ - DisasCompare cmp; \ - cond = GET_FIELD_SP(insn, 14, 17); \ - gen_compare(&cmp, xcc, cond, dc); \ - gen_fmov##sz(dc, &cmp, rd, rs2); \ - free_compare(&cmp); \ - } while (0) - - case 0x101: /* V9 fmovscc %icc */ - FMOVCC(0, s); - break; - case 0x102: /* V9 fmovdcc %icc */ - FMOVCC(0, d); - break; - case 0x103: /* V9 fmovqcc %icc */ - CHECK_FPU_FEATURE(dc, FLOAT128); - FMOVCC(0, q); - break; - case 0x181: /* V9 fmovscc %xcc */ - FMOVCC(1, s); - break; - case 0x182: /* V9 fmovdcc %xcc */ - FMOVCC(1, d); - break; - case 0x183: /* V9 fmovqcc %xcc */ - CHECK_FPU_FEATURE(dc, FLOAT128); - FMOVCC(1, q); - break; -#undef FMOVCC -#endif - case 0x51: /* fcmps, V9 %fcc */ - cpu_src1_32 = gen_load_fpr_F(dc, rs1); - cpu_src2_32 = gen_load_fpr_F(dc, rs2); - gen_op_fcmps(rd & 3, cpu_src1_32, cpu_src2_32); - break; - case 0x52: /* fcmpd, V9 %fcc */ - cpu_src1_64 = gen_load_fpr_D(dc, rs1); - cpu_src2_64 = gen_load_fpr_D(dc, rs2); - gen_op_fcmpd(rd & 3, cpu_src1_64, cpu_src2_64); - break; - case 0x53: /* fcmpq, V9 %fcc */ - CHECK_FPU_FEATURE(dc, FLOAT128); - gen_op_load_fpr_QT0(QFPREG(rs1)); - gen_op_load_fpr_QT1(QFPREG(rs2)); - gen_op_fcmpq(rd & 3); - break; - case 0x55: /* fcmpes, V9 %fcc */ - cpu_src1_32 = gen_load_fpr_F(dc, rs1); - cpu_src2_32 = gen_load_fpr_F(dc, rs2); - gen_op_fcmpes(rd & 3, cpu_src1_32, cpu_src2_32); - break; - case 0x56: /* fcmped, V9 %fcc */ - cpu_src1_64 = gen_load_fpr_D(dc, rs1); - cpu_src2_64 = gen_load_fpr_D(dc, rs2); - gen_op_fcmped(rd & 3, cpu_src1_64, cpu_src2_64); - break; - case 0x57: /* fcmpeq, V9 %fcc */ - CHECK_FPU_FEATURE(dc, FLOAT128); - gen_op_load_fpr_QT0(QFPREG(rs1)); - gen_op_load_fpr_QT1(QFPREG(rs2)); - gen_op_fcmpeq(rd & 3); - break; - default: - goto illegal_insn; - } - } else if (xop == 0x2) { - TCGv dst = gen_dest_gpr(dc, rd); - rs1 = GET_FIELD(insn, 13, 17); - if (rs1 == 0) { - /* clr/mov shortcut : or %g0, x, y -> mov x, y */ - if (IS_IMM) { /* immediate */ - simm = GET_FIELDs(insn, 19, 31); - tcg_gen_movi_tl(dst, simm); - gen_store_gpr(dc, rd, dst); - } else { /* register */ - rs2 = GET_FIELD(insn, 27, 31); - if (rs2 == 0) { - tcg_gen_movi_tl(dst, 0); - gen_store_gpr(dc, rd, dst); - } else { - cpu_src2 = gen_load_gpr(dc, rs2); - gen_store_gpr(dc, rd, cpu_src2); - } - } - } else { - cpu_src1 = get_src1(dc, insn); - if (IS_IMM) { /* immediate */ - simm = GET_FIELDs(insn, 19, 31); - tcg_gen_ori_tl(dst, cpu_src1, simm); - gen_store_gpr(dc, rd, dst); - } else { /* register */ - rs2 = GET_FIELD(insn, 27, 31); - if (rs2 == 0) { - /* mov shortcut: or x, %g0, y -> mov x, y */ - gen_store_gpr(dc, rd, cpu_src1); - } else { - cpu_src2 = gen_load_gpr(dc, rs2); - tcg_gen_or_tl(dst, cpu_src1, cpu_src2); - gen_store_gpr(dc, rd, dst); - } - } - } -#ifdef TARGET_SPARC64 - } else if (xop == 0x25) { /* sll, V9 sllx */ - cpu_src1 = get_src1(dc, insn); - if (IS_IMM) { /* immediate */ - simm = GET_FIELDs(insn, 20, 31); - if (insn & (1 << 12)) { - tcg_gen_shli_i64(cpu_dst, cpu_src1, simm & 0x3f); - } else { - tcg_gen_shli_i64(cpu_dst, cpu_src1, simm & 0x1f); - } - } else { /* register */ - rs2 = GET_FIELD(insn, 27, 31); - cpu_src2 = gen_load_gpr(dc, rs2); - cpu_tmp0 = get_temp_tl(dc); - if (insn & (1 << 12)) { - tcg_gen_andi_i64(cpu_tmp0, cpu_src2, 0x3f); - } else { - tcg_gen_andi_i64(cpu_tmp0, cpu_src2, 0x1f); - } - tcg_gen_shl_i64(cpu_dst, cpu_src1, cpu_tmp0); - } - gen_store_gpr(dc, rd, cpu_dst); - } else if (xop == 0x26) { /* srl, V9 srlx */ - cpu_src1 = get_src1(dc, insn); - if (IS_IMM) { /* immediate */ - simm = GET_FIELDs(insn, 20, 31); - if (insn & (1 << 12)) { - tcg_gen_shri_i64(cpu_dst, cpu_src1, simm & 0x3f); - } else { - tcg_gen_andi_i64(cpu_dst, cpu_src1, 0xffffffffULL); - tcg_gen_shri_i64(cpu_dst, cpu_dst, simm & 0x1f); - } - } else { /* register */ - rs2 = GET_FIELD(insn, 27, 31); - cpu_src2 = gen_load_gpr(dc, rs2); - cpu_tmp0 = get_temp_tl(dc); - if (insn & (1 << 12)) { - tcg_gen_andi_i64(cpu_tmp0, cpu_src2, 0x3f); - tcg_gen_shr_i64(cpu_dst, cpu_src1, cpu_tmp0); - } else { - tcg_gen_andi_i64(cpu_tmp0, cpu_src2, 0x1f); - tcg_gen_andi_i64(cpu_dst, cpu_src1, 0xffffffffULL); - tcg_gen_shr_i64(cpu_dst, cpu_dst, cpu_tmp0); - } - } - gen_store_gpr(dc, rd, cpu_dst); - } else if (xop == 0x27) { /* sra, V9 srax */ - cpu_src1 = get_src1(dc, insn); - if (IS_IMM) { /* immediate */ - simm = GET_FIELDs(insn, 20, 31); - if (insn & (1 << 12)) { - tcg_gen_sari_i64(cpu_dst, cpu_src1, simm & 0x3f); - } else { - tcg_gen_ext32s_i64(cpu_dst, cpu_src1); - tcg_gen_sari_i64(cpu_dst, cpu_dst, simm & 0x1f); - } - } else { /* register */ - rs2 = GET_FIELD(insn, 27, 31); - cpu_src2 = gen_load_gpr(dc, rs2); - cpu_tmp0 = get_temp_tl(dc); - if (insn & (1 << 12)) { - tcg_gen_andi_i64(cpu_tmp0, cpu_src2, 0x3f); - tcg_gen_sar_i64(cpu_dst, cpu_src1, cpu_tmp0); - } else { - tcg_gen_andi_i64(cpu_tmp0, cpu_src2, 0x1f); - tcg_gen_ext32s_i64(cpu_dst, cpu_src1); - tcg_gen_sar_i64(cpu_dst, cpu_dst, cpu_tmp0); - } - } - gen_store_gpr(dc, rd, cpu_dst); -#endif - } else if (xop < 0x36) { - if (xop < 0x20) { - cpu_src1 = get_src1(dc, insn); - cpu_src2 = get_src2(dc, insn); - switch (xop & ~0x10) { - case 0x0: /* add */ - if (xop & 0x10) { - gen_op_add_cc(cpu_dst, cpu_src1, cpu_src2); - tcg_gen_movi_i32(cpu_cc_op, CC_OP_ADD); - dc->cc_op = CC_OP_ADD; - } else { - tcg_gen_add_tl(cpu_dst, cpu_src1, cpu_src2); - } - break; - case 0x1: /* and */ - tcg_gen_and_tl(cpu_dst, cpu_src1, cpu_src2); - if (xop & 0x10) { - tcg_gen_mov_tl(cpu_cc_dst, cpu_dst); - tcg_gen_movi_i32(cpu_cc_op, CC_OP_LOGIC); - dc->cc_op = CC_OP_LOGIC; - } - break; - case 0x2: /* or */ - tcg_gen_or_tl(cpu_dst, cpu_src1, cpu_src2); - if (xop & 0x10) { - tcg_gen_mov_tl(cpu_cc_dst, cpu_dst); - tcg_gen_movi_i32(cpu_cc_op, CC_OP_LOGIC); - dc->cc_op = CC_OP_LOGIC; - } - break; - case 0x3: /* xor */ - tcg_gen_xor_tl(cpu_dst, cpu_src1, cpu_src2); - if (xop & 0x10) { - tcg_gen_mov_tl(cpu_cc_dst, cpu_dst); - tcg_gen_movi_i32(cpu_cc_op, CC_OP_LOGIC); - dc->cc_op = CC_OP_LOGIC; - } - break; - case 0x4: /* sub */ - if (xop & 0x10) { - gen_op_sub_cc(cpu_dst, cpu_src1, cpu_src2); - tcg_gen_movi_i32(cpu_cc_op, CC_OP_SUB); - dc->cc_op = CC_OP_SUB; - } else { - tcg_gen_sub_tl(cpu_dst, cpu_src1, cpu_src2); - } - break; - case 0x5: /* andn */ - tcg_gen_andc_tl(cpu_dst, cpu_src1, cpu_src2); - if (xop & 0x10) { - tcg_gen_mov_tl(cpu_cc_dst, cpu_dst); - tcg_gen_movi_i32(cpu_cc_op, CC_OP_LOGIC); - dc->cc_op = CC_OP_LOGIC; - } - break; - case 0x6: /* orn */ - tcg_gen_orc_tl(cpu_dst, cpu_src1, cpu_src2); - if (xop & 0x10) { - tcg_gen_mov_tl(cpu_cc_dst, cpu_dst); - tcg_gen_movi_i32(cpu_cc_op, CC_OP_LOGIC); - dc->cc_op = CC_OP_LOGIC; - } - break; - case 0x7: /* xorn */ - tcg_gen_eqv_tl(cpu_dst, cpu_src1, cpu_src2); - if (xop & 0x10) { - tcg_gen_mov_tl(cpu_cc_dst, cpu_dst); - tcg_gen_movi_i32(cpu_cc_op, CC_OP_LOGIC); - dc->cc_op = CC_OP_LOGIC; - } - break; - case 0x8: /* addx, V9 addc */ - gen_op_addx_int(dc, cpu_dst, cpu_src1, cpu_src2, - (xop & 0x10)); - break; -#ifdef TARGET_SPARC64 - case 0x9: /* V9 mulx */ - tcg_gen_mul_i64(cpu_dst, cpu_src1, cpu_src2); - break; -#endif - case 0xa: /* umul */ - CHECK_IU_FEATURE(dc, MUL); - gen_op_umul(cpu_dst, cpu_src1, cpu_src2); - if (xop & 0x10) { - tcg_gen_mov_tl(cpu_cc_dst, cpu_dst); - tcg_gen_movi_i32(cpu_cc_op, CC_OP_LOGIC); - dc->cc_op = CC_OP_LOGIC; - } - break; - case 0xb: /* smul */ - CHECK_IU_FEATURE(dc, MUL); - gen_op_smul(cpu_dst, cpu_src1, cpu_src2); - if (xop & 0x10) { - tcg_gen_mov_tl(cpu_cc_dst, cpu_dst); - tcg_gen_movi_i32(cpu_cc_op, CC_OP_LOGIC); - dc->cc_op = CC_OP_LOGIC; - } - break; - case 0xc: /* subx, V9 subc */ - gen_op_subx_int(dc, cpu_dst, cpu_src1, cpu_src2, - (xop & 0x10)); - break; -#ifdef TARGET_SPARC64 - case 0xd: /* V9 udivx */ - gen_helper_udivx(cpu_dst, cpu_env, cpu_src1, cpu_src2); - break; -#endif - case 0xe: /* udiv */ - CHECK_IU_FEATURE(dc, DIV); - if (xop & 0x10) { - gen_helper_udiv_cc(cpu_dst, cpu_env, cpu_src1, - cpu_src2); - dc->cc_op = CC_OP_DIV; - } else { - gen_helper_udiv(cpu_dst, cpu_env, cpu_src1, - cpu_src2); - } - break; - case 0xf: /* sdiv */ - CHECK_IU_FEATURE(dc, DIV); - if (xop & 0x10) { - gen_helper_sdiv_cc(cpu_dst, cpu_env, cpu_src1, - cpu_src2); - dc->cc_op = CC_OP_DIV; - } else { - gen_helper_sdiv(cpu_dst, cpu_env, cpu_src1, - cpu_src2); - } - break; - default: - goto illegal_insn; - } - gen_store_gpr(dc, rd, cpu_dst); - } else { - cpu_src1 = get_src1(dc, insn); - cpu_src2 = get_src2(dc, insn); - switch (xop) { - case 0x20: /* taddcc */ - gen_op_add_cc(cpu_dst, cpu_src1, cpu_src2); - gen_store_gpr(dc, rd, cpu_dst); - tcg_gen_movi_i32(cpu_cc_op, CC_OP_TADD); - dc->cc_op = CC_OP_TADD; - break; - case 0x21: /* tsubcc */ - gen_op_sub_cc(cpu_dst, cpu_src1, cpu_src2); - gen_store_gpr(dc, rd, cpu_dst); - tcg_gen_movi_i32(cpu_cc_op, CC_OP_TSUB); - dc->cc_op = CC_OP_TSUB; - break; - case 0x22: /* taddcctv */ - gen_helper_taddcctv(cpu_dst, cpu_env, - cpu_src1, cpu_src2); - gen_store_gpr(dc, rd, cpu_dst); - dc->cc_op = CC_OP_TADDTV; - break; - case 0x23: /* tsubcctv */ - gen_helper_tsubcctv(cpu_dst, cpu_env, - cpu_src1, cpu_src2); - gen_store_gpr(dc, rd, cpu_dst); - dc->cc_op = CC_OP_TSUBTV; - break; - case 0x24: /* mulscc */ - update_psr(dc); - gen_op_mulscc(cpu_dst, cpu_src1, cpu_src2); - gen_store_gpr(dc, rd, cpu_dst); - tcg_gen_movi_i32(cpu_cc_op, CC_OP_ADD); - dc->cc_op = CC_OP_ADD; - break; -#ifndef TARGET_SPARC64 - case 0x25: /* sll */ - if (IS_IMM) { /* immediate */ - simm = GET_FIELDs(insn, 20, 31); - tcg_gen_shli_tl(cpu_dst, cpu_src1, simm & 0x1f); - } else { /* register */ - cpu_tmp0 = get_temp_tl(dc); - tcg_gen_andi_tl(cpu_tmp0, cpu_src2, 0x1f); - tcg_gen_shl_tl(cpu_dst, cpu_src1, cpu_tmp0); - } - gen_store_gpr(dc, rd, cpu_dst); - break; - case 0x26: /* srl */ - if (IS_IMM) { /* immediate */ - simm = GET_FIELDs(insn, 20, 31); - tcg_gen_shri_tl(cpu_dst, cpu_src1, simm & 0x1f); - } else { /* register */ - cpu_tmp0 = get_temp_tl(dc); - tcg_gen_andi_tl(cpu_tmp0, cpu_src2, 0x1f); - tcg_gen_shr_tl(cpu_dst, cpu_src1, cpu_tmp0); - } - gen_store_gpr(dc, rd, cpu_dst); - break; - case 0x27: /* sra */ - if (IS_IMM) { /* immediate */ - simm = GET_FIELDs(insn, 20, 31); - tcg_gen_sari_tl(cpu_dst, cpu_src1, simm & 0x1f); - } else { /* register */ - cpu_tmp0 = get_temp_tl(dc); - tcg_gen_andi_tl(cpu_tmp0, cpu_src2, 0x1f); - tcg_gen_sar_tl(cpu_dst, cpu_src1, cpu_tmp0); - } - gen_store_gpr(dc, rd, cpu_dst); - break; -#endif - case 0x30: - { - cpu_tmp0 = get_temp_tl(dc); - switch(rd) { - case 0: /* wry */ - tcg_gen_xor_tl(cpu_tmp0, cpu_src1, cpu_src2); - tcg_gen_andi_tl(cpu_y, cpu_tmp0, 0xffffffff); - break; -#ifndef TARGET_SPARC64 - case 0x01 ... 0x0f: /* undefined in the - SPARCv8 manual, nop - on the microSPARC - II */ - case 0x10 ... 0x1f: /* implementation-dependent - in the SPARCv8 - manual, nop on the - microSPARC II */ - if ((rd == 0x13) && (dc->def->features & - CPU_FEATURE_POWERDOWN)) { - /* LEON3 power-down */ - save_state(dc); - gen_helper_power_down(cpu_env); - } - break; -#else - case 0x2: /* V9 wrccr */ - tcg_gen_xor_tl(cpu_tmp0, cpu_src1, cpu_src2); - gen_helper_wrccr(cpu_env, cpu_tmp0); - tcg_gen_movi_i32(cpu_cc_op, CC_OP_FLAGS); - dc->cc_op = CC_OP_FLAGS; - break; - case 0x3: /* V9 wrasi */ - tcg_gen_xor_tl(cpu_tmp0, cpu_src1, cpu_src2); - tcg_gen_andi_tl(cpu_tmp0, cpu_tmp0, 0xff); - tcg_gen_trunc_tl_i32(cpu_asi, cpu_tmp0); - break; - case 0x6: /* V9 wrfprs */ - tcg_gen_xor_tl(cpu_tmp0, cpu_src1, cpu_src2); - tcg_gen_trunc_tl_i32(cpu_fprs, cpu_tmp0); - save_state(dc); - gen_op_next_insn(); - tcg_gen_exit_tb(0); - dc->is_br = 1; - break; - case 0xf: /* V9 sir, nop if user */ -#if !defined(CONFIG_USER_ONLY) - if (supervisor(dc)) { - ; // XXX - } -#endif - break; - case 0x13: /* Graphics Status */ - if (gen_trap_ifnofpu(dc)) { - goto jmp_insn; - } - tcg_gen_xor_tl(cpu_gsr, cpu_src1, cpu_src2); - break; - case 0x14: /* Softint set */ - if (!supervisor(dc)) - goto illegal_insn; - tcg_gen_xor_tl(cpu_tmp0, cpu_src1, cpu_src2); - gen_helper_set_softint(cpu_env, cpu_tmp0); - break; - case 0x15: /* Softint clear */ - if (!supervisor(dc)) - goto illegal_insn; - tcg_gen_xor_tl(cpu_tmp0, cpu_src1, cpu_src2); - gen_helper_clear_softint(cpu_env, cpu_tmp0); - break; - case 0x16: /* Softint write */ - if (!supervisor(dc)) - goto illegal_insn; - tcg_gen_xor_tl(cpu_tmp0, cpu_src1, cpu_src2); - gen_helper_write_softint(cpu_env, cpu_tmp0); - break; - case 0x17: /* Tick compare */ -#if !defined(CONFIG_USER_ONLY) - if (!supervisor(dc)) - goto illegal_insn; -#endif - { - TCGv_ptr r_tickptr; - - tcg_gen_xor_tl(cpu_tick_cmpr, cpu_src1, - cpu_src2); - r_tickptr = tcg_temp_new_ptr(); - tcg_gen_ld_ptr(r_tickptr, cpu_env, - offsetof(CPUSPARCState, tick)); - gen_helper_tick_set_limit(r_tickptr, - cpu_tick_cmpr); - tcg_temp_free_ptr(r_tickptr); - } - break; - case 0x18: /* System tick */ -#if !defined(CONFIG_USER_ONLY) - if (!supervisor(dc)) - goto illegal_insn; -#endif - { - TCGv_ptr r_tickptr; - - tcg_gen_xor_tl(cpu_tmp0, cpu_src1, - cpu_src2); - r_tickptr = tcg_temp_new_ptr(); - tcg_gen_ld_ptr(r_tickptr, cpu_env, - offsetof(CPUSPARCState, stick)); - gen_helper_tick_set_count(r_tickptr, - cpu_tmp0); - tcg_temp_free_ptr(r_tickptr); - } - break; - case 0x19: /* System tick compare */ -#if !defined(CONFIG_USER_ONLY) - if (!supervisor(dc)) - goto illegal_insn; -#endif - { - TCGv_ptr r_tickptr; - - tcg_gen_xor_tl(cpu_stick_cmpr, cpu_src1, - cpu_src2); - r_tickptr = tcg_temp_new_ptr(); - tcg_gen_ld_ptr(r_tickptr, cpu_env, - offsetof(CPUSPARCState, stick)); - gen_helper_tick_set_limit(r_tickptr, - cpu_stick_cmpr); - tcg_temp_free_ptr(r_tickptr); - } - break; - - case 0x10: /* Performance Control */ - case 0x11: /* Performance Instrumentation - Counter */ - case 0x12: /* Dispatch Control */ -#endif - default: - goto illegal_insn; - } - } - break; -#if !defined(CONFIG_USER_ONLY) - case 0x31: /* wrpsr, V9 saved, restored */ - { - if (!supervisor(dc)) - goto priv_insn; -#ifdef TARGET_SPARC64 - switch (rd) { - case 0: - gen_helper_saved(cpu_env); - break; - case 1: - gen_helper_restored(cpu_env); - break; - case 2: /* UA2005 allclean */ - case 3: /* UA2005 otherw */ - case 4: /* UA2005 normalw */ - case 5: /* UA2005 invalw */ - // XXX - default: - goto illegal_insn; - } -#else - cpu_tmp0 = get_temp_tl(dc); - tcg_gen_xor_tl(cpu_tmp0, cpu_src1, cpu_src2); - gen_helper_wrpsr(cpu_env, cpu_tmp0); - tcg_gen_movi_i32(cpu_cc_op, CC_OP_FLAGS); - dc->cc_op = CC_OP_FLAGS; - save_state(dc); - gen_op_next_insn(); - tcg_gen_exit_tb(0); - dc->is_br = 1; -#endif - } - break; - case 0x32: /* wrwim, V9 wrpr */ - { - if (!supervisor(dc)) - goto priv_insn; - cpu_tmp0 = get_temp_tl(dc); - tcg_gen_xor_tl(cpu_tmp0, cpu_src1, cpu_src2); -#ifdef TARGET_SPARC64 - switch (rd) { - case 0: // tpc - { - TCGv_ptr r_tsptr; - - r_tsptr = tcg_temp_new_ptr(); - gen_load_trap_state_at_tl(r_tsptr, cpu_env); - tcg_gen_st_tl(cpu_tmp0, r_tsptr, - offsetof(trap_state, tpc)); - tcg_temp_free_ptr(r_tsptr); - } - break; - case 1: // tnpc - { - TCGv_ptr r_tsptr; - - r_tsptr = tcg_temp_new_ptr(); - gen_load_trap_state_at_tl(r_tsptr, cpu_env); - tcg_gen_st_tl(cpu_tmp0, r_tsptr, - offsetof(trap_state, tnpc)); - tcg_temp_free_ptr(r_tsptr); - } - break; - case 2: // tstate - { - TCGv_ptr r_tsptr; - - r_tsptr = tcg_temp_new_ptr(); - gen_load_trap_state_at_tl(r_tsptr, cpu_env); - tcg_gen_st_tl(cpu_tmp0, r_tsptr, - offsetof(trap_state, - tstate)); - tcg_temp_free_ptr(r_tsptr); - } - break; - case 3: // tt - { - TCGv_ptr r_tsptr; - - r_tsptr = tcg_temp_new_ptr(); - gen_load_trap_state_at_tl(r_tsptr, cpu_env); - tcg_gen_st32_tl(cpu_tmp0, r_tsptr, - offsetof(trap_state, tt)); - tcg_temp_free_ptr(r_tsptr); - } - break; - case 4: // tick - { - TCGv_ptr r_tickptr; - - r_tickptr = tcg_temp_new_ptr(); - tcg_gen_ld_ptr(r_tickptr, cpu_env, - offsetof(CPUSPARCState, tick)); - gen_helper_tick_set_count(r_tickptr, - cpu_tmp0); - tcg_temp_free_ptr(r_tickptr); - } - break; - case 5: // tba - tcg_gen_mov_tl(cpu_tbr, cpu_tmp0); - break; - case 6: // pstate - save_state(dc); - gen_helper_wrpstate(cpu_env, cpu_tmp0); - dc->npc = DYNAMIC_PC; - break; - case 7: // tl - save_state(dc); - tcg_gen_st32_tl(cpu_tmp0, cpu_env, - offsetof(CPUSPARCState, tl)); - dc->npc = DYNAMIC_PC; - break; - case 8: // pil - gen_helper_wrpil(cpu_env, cpu_tmp0); - break; - case 9: // cwp - gen_helper_wrcwp(cpu_env, cpu_tmp0); - break; - case 10: // cansave - tcg_gen_st32_tl(cpu_tmp0, cpu_env, - offsetof(CPUSPARCState, - cansave)); - break; - case 11: // canrestore - tcg_gen_st32_tl(cpu_tmp0, cpu_env, - offsetof(CPUSPARCState, - canrestore)); - break; - case 12: // cleanwin - tcg_gen_st32_tl(cpu_tmp0, cpu_env, - offsetof(CPUSPARCState, - cleanwin)); - break; - case 13: // otherwin - tcg_gen_st32_tl(cpu_tmp0, cpu_env, - offsetof(CPUSPARCState, - otherwin)); - break; - case 14: // wstate - tcg_gen_st32_tl(cpu_tmp0, cpu_env, - offsetof(CPUSPARCState, - wstate)); - break; - case 16: // UA2005 gl - CHECK_IU_FEATURE(dc, GL); - tcg_gen_st32_tl(cpu_tmp0, cpu_env, - offsetof(CPUSPARCState, gl)); - break; - case 26: // UA2005 strand status - CHECK_IU_FEATURE(dc, HYPV); - if (!hypervisor(dc)) - goto priv_insn; - tcg_gen_mov_tl(cpu_ssr, cpu_tmp0); - break; - default: - goto illegal_insn; - } -#else - tcg_gen_trunc_tl_i32(cpu_wim, cpu_tmp0); - if (dc->def->nwindows != 32) { - tcg_gen_andi_tl(cpu_wim, cpu_wim, - (1 << dc->def->nwindows) - 1); - } -#endif - } - break; - case 0x33: /* wrtbr, UA2005 wrhpr */ - { -#ifndef TARGET_SPARC64 - if (!supervisor(dc)) - goto priv_insn; - tcg_gen_xor_tl(cpu_tbr, cpu_src1, cpu_src2); -#else - CHECK_IU_FEATURE(dc, HYPV); - if (!hypervisor(dc)) - goto priv_insn; - cpu_tmp0 = get_temp_tl(dc); - tcg_gen_xor_tl(cpu_tmp0, cpu_src1, cpu_src2); - switch (rd) { - case 0: // hpstate - // XXX gen_op_wrhpstate(); - save_state(dc); - gen_op_next_insn(); - tcg_gen_exit_tb(0); - dc->is_br = 1; - break; - case 1: // htstate - // XXX gen_op_wrhtstate(); - break; - case 3: // hintp - tcg_gen_mov_tl(cpu_hintp, cpu_tmp0); - break; - case 5: // htba - tcg_gen_mov_tl(cpu_htba, cpu_tmp0); - break; - case 31: // hstick_cmpr - { - TCGv_ptr r_tickptr; - - tcg_gen_mov_tl(cpu_hstick_cmpr, cpu_tmp0); - r_tickptr = tcg_temp_new_ptr(); - tcg_gen_ld_ptr(r_tickptr, cpu_env, - offsetof(CPUSPARCState, hstick)); - gen_helper_tick_set_limit(r_tickptr, - cpu_hstick_cmpr); - tcg_temp_free_ptr(r_tickptr); - } - break; - case 6: // hver readonly - default: - goto illegal_insn; - } -#endif - } - break; -#endif -#ifdef TARGET_SPARC64 - case 0x2c: /* V9 movcc */ - { - int cc = GET_FIELD_SP(insn, 11, 12); - int cond = GET_FIELD_SP(insn, 14, 17); - DisasCompare cmp; - TCGv dst; - - if (insn & (1 << 18)) { - if (cc == 0) { - gen_compare(&cmp, 0, cond, dc); - } else if (cc == 2) { - gen_compare(&cmp, 1, cond, dc); - } else { - goto illegal_insn; - } - } else { - gen_fcompare(&cmp, cc, cond); - } - - /* The get_src2 above loaded the normal 13-bit - immediate field, not the 11-bit field we have - in movcc. But it did handle the reg case. */ - if (IS_IMM) { - simm = GET_FIELD_SPs(insn, 0, 10); - tcg_gen_movi_tl(cpu_src2, simm); - } - - dst = gen_load_gpr(dc, rd); - tcg_gen_movcond_tl(cmp.cond, dst, - cmp.c1, cmp.c2, - cpu_src2, dst); - free_compare(&cmp); - gen_store_gpr(dc, rd, dst); - break; - } - case 0x2d: /* V9 sdivx */ - gen_helper_sdivx(cpu_dst, cpu_env, cpu_src1, cpu_src2); - gen_store_gpr(dc, rd, cpu_dst); - break; - case 0x2e: /* V9 popc */ - gen_helper_popc(cpu_dst, cpu_src2); - gen_store_gpr(dc, rd, cpu_dst); - break; - case 0x2f: /* V9 movr */ - { - int cond = GET_FIELD_SP(insn, 10, 12); - DisasCompare cmp; - TCGv dst; - - gen_compare_reg(&cmp, cond, cpu_src1); - - /* The get_src2 above loaded the normal 13-bit - immediate field, not the 10-bit field we have - in movr. But it did handle the reg case. */ - if (IS_IMM) { - simm = GET_FIELD_SPs(insn, 0, 9); - tcg_gen_movi_tl(cpu_src2, simm); - } - - dst = gen_load_gpr(dc, rd); - tcg_gen_movcond_tl(cmp.cond, dst, - cmp.c1, cmp.c2, - cpu_src2, dst); - free_compare(&cmp); - gen_store_gpr(dc, rd, dst); - break; - } -#endif - default: - goto illegal_insn; - } - } - } else if (xop == 0x36) { /* UltraSparc shutdown, VIS, V8 CPop1 */ -#ifdef TARGET_SPARC64 - int opf = GET_FIELD_SP(insn, 5, 13); - rs1 = GET_FIELD(insn, 13, 17); - rs2 = GET_FIELD(insn, 27, 31); - if (gen_trap_ifnofpu(dc)) { - goto jmp_insn; - } - - switch (opf) { - case 0x000: /* VIS I edge8cc */ - CHECK_FPU_FEATURE(dc, VIS1); - cpu_src1 = gen_load_gpr(dc, rs1); - cpu_src2 = gen_load_gpr(dc, rs2); - gen_edge(dc, cpu_dst, cpu_src1, cpu_src2, 8, 1, 0); - gen_store_gpr(dc, rd, cpu_dst); - break; - case 0x001: /* VIS II edge8n */ - CHECK_FPU_FEATURE(dc, VIS2); - cpu_src1 = gen_load_gpr(dc, rs1); - cpu_src2 = gen_load_gpr(dc, rs2); - gen_edge(dc, cpu_dst, cpu_src1, cpu_src2, 8, 0, 0); - gen_store_gpr(dc, rd, cpu_dst); - break; - case 0x002: /* VIS I edge8lcc */ - CHECK_FPU_FEATURE(dc, VIS1); - cpu_src1 = gen_load_gpr(dc, rs1); - cpu_src2 = gen_load_gpr(dc, rs2); - gen_edge(dc, cpu_dst, cpu_src1, cpu_src2, 8, 1, 1); - gen_store_gpr(dc, rd, cpu_dst); - break; - case 0x003: /* VIS II edge8ln */ - CHECK_FPU_FEATURE(dc, VIS2); - cpu_src1 = gen_load_gpr(dc, rs1); - cpu_src2 = gen_load_gpr(dc, rs2); - gen_edge(dc, cpu_dst, cpu_src1, cpu_src2, 8, 0, 1); - gen_store_gpr(dc, rd, cpu_dst); - break; - case 0x004: /* VIS I edge16cc */ - CHECK_FPU_FEATURE(dc, VIS1); - cpu_src1 = gen_load_gpr(dc, rs1); - cpu_src2 = gen_load_gpr(dc, rs2); - gen_edge(dc, cpu_dst, cpu_src1, cpu_src2, 16, 1, 0); - gen_store_gpr(dc, rd, cpu_dst); - break; - case 0x005: /* VIS II edge16n */ - CHECK_FPU_FEATURE(dc, VIS2); - cpu_src1 = gen_load_gpr(dc, rs1); - cpu_src2 = gen_load_gpr(dc, rs2); - gen_edge(dc, cpu_dst, cpu_src1, cpu_src2, 16, 0, 0); - gen_store_gpr(dc, rd, cpu_dst); - break; - case 0x006: /* VIS I edge16lcc */ - CHECK_FPU_FEATURE(dc, VIS1); - cpu_src1 = gen_load_gpr(dc, rs1); - cpu_src2 = gen_load_gpr(dc, rs2); - gen_edge(dc, cpu_dst, cpu_src1, cpu_src2, 16, 1, 1); - gen_store_gpr(dc, rd, cpu_dst); - break; - case 0x007: /* VIS II edge16ln */ - CHECK_FPU_FEATURE(dc, VIS2); - cpu_src1 = gen_load_gpr(dc, rs1); - cpu_src2 = gen_load_gpr(dc, rs2); - gen_edge(dc, cpu_dst, cpu_src1, cpu_src2, 16, 0, 1); - gen_store_gpr(dc, rd, cpu_dst); - break; - case 0x008: /* VIS I edge32cc */ - CHECK_FPU_FEATURE(dc, VIS1); - cpu_src1 = gen_load_gpr(dc, rs1); - cpu_src2 = gen_load_gpr(dc, rs2); - gen_edge(dc, cpu_dst, cpu_src1, cpu_src2, 32, 1, 0); - gen_store_gpr(dc, rd, cpu_dst); - break; - case 0x009: /* VIS II edge32n */ - CHECK_FPU_FEATURE(dc, VIS2); - cpu_src1 = gen_load_gpr(dc, rs1); - cpu_src2 = gen_load_gpr(dc, rs2); - gen_edge(dc, cpu_dst, cpu_src1, cpu_src2, 32, 0, 0); - gen_store_gpr(dc, rd, cpu_dst); - break; - case 0x00a: /* VIS I edge32lcc */ - CHECK_FPU_FEATURE(dc, VIS1); - cpu_src1 = gen_load_gpr(dc, rs1); - cpu_src2 = gen_load_gpr(dc, rs2); - gen_edge(dc, cpu_dst, cpu_src1, cpu_src2, 32, 1, 1); - gen_store_gpr(dc, rd, cpu_dst); - break; - case 0x00b: /* VIS II edge32ln */ - CHECK_FPU_FEATURE(dc, VIS2); - cpu_src1 = gen_load_gpr(dc, rs1); - cpu_src2 = gen_load_gpr(dc, rs2); - gen_edge(dc, cpu_dst, cpu_src1, cpu_src2, 32, 0, 1); - gen_store_gpr(dc, rd, cpu_dst); - break; - case 0x010: /* VIS I array8 */ - CHECK_FPU_FEATURE(dc, VIS1); - cpu_src1 = gen_load_gpr(dc, rs1); - cpu_src2 = gen_load_gpr(dc, rs2); - gen_helper_array8(cpu_dst, cpu_src1, cpu_src2); - gen_store_gpr(dc, rd, cpu_dst); - break; - case 0x012: /* VIS I array16 */ - CHECK_FPU_FEATURE(dc, VIS1); - cpu_src1 = gen_load_gpr(dc, rs1); - cpu_src2 = gen_load_gpr(dc, rs2); - gen_helper_array8(cpu_dst, cpu_src1, cpu_src2); - tcg_gen_shli_i64(cpu_dst, cpu_dst, 1); - gen_store_gpr(dc, rd, cpu_dst); - break; - case 0x014: /* VIS I array32 */ - CHECK_FPU_FEATURE(dc, VIS1); - cpu_src1 = gen_load_gpr(dc, rs1); - cpu_src2 = gen_load_gpr(dc, rs2); - gen_helper_array8(cpu_dst, cpu_src1, cpu_src2); - tcg_gen_shli_i64(cpu_dst, cpu_dst, 2); - gen_store_gpr(dc, rd, cpu_dst); - break; - case 0x018: /* VIS I alignaddr */ - CHECK_FPU_FEATURE(dc, VIS1); - cpu_src1 = gen_load_gpr(dc, rs1); - cpu_src2 = gen_load_gpr(dc, rs2); - gen_alignaddr(cpu_dst, cpu_src1, cpu_src2, 0); - gen_store_gpr(dc, rd, cpu_dst); - break; - case 0x01a: /* VIS I alignaddrl */ - CHECK_FPU_FEATURE(dc, VIS1); - cpu_src1 = gen_load_gpr(dc, rs1); - cpu_src2 = gen_load_gpr(dc, rs2); - gen_alignaddr(cpu_dst, cpu_src1, cpu_src2, 1); - gen_store_gpr(dc, rd, cpu_dst); - break; - case 0x019: /* VIS II bmask */ - CHECK_FPU_FEATURE(dc, VIS2); - cpu_src1 = gen_load_gpr(dc, rs1); - cpu_src2 = gen_load_gpr(dc, rs2); - tcg_gen_add_tl(cpu_dst, cpu_src1, cpu_src2); - tcg_gen_deposit_tl(cpu_gsr, cpu_gsr, cpu_dst, 32, 32); - gen_store_gpr(dc, rd, cpu_dst); - break; - case 0x020: /* VIS I fcmple16 */ - CHECK_FPU_FEATURE(dc, VIS1); - cpu_src1_64 = gen_load_fpr_D(dc, rs1); - cpu_src2_64 = gen_load_fpr_D(dc, rs2); - gen_helper_fcmple16(cpu_dst, cpu_src1_64, cpu_src2_64); - gen_store_gpr(dc, rd, cpu_dst); - break; - case 0x022: /* VIS I fcmpne16 */ - CHECK_FPU_FEATURE(dc, VIS1); - cpu_src1_64 = gen_load_fpr_D(dc, rs1); - cpu_src2_64 = gen_load_fpr_D(dc, rs2); - gen_helper_fcmpne16(cpu_dst, cpu_src1_64, cpu_src2_64); - gen_store_gpr(dc, rd, cpu_dst); - break; - case 0x024: /* VIS I fcmple32 */ - CHECK_FPU_FEATURE(dc, VIS1); - cpu_src1_64 = gen_load_fpr_D(dc, rs1); - cpu_src2_64 = gen_load_fpr_D(dc, rs2); - gen_helper_fcmple32(cpu_dst, cpu_src1_64, cpu_src2_64); - gen_store_gpr(dc, rd, cpu_dst); - break; - case 0x026: /* VIS I fcmpne32 */ - CHECK_FPU_FEATURE(dc, VIS1); - cpu_src1_64 = gen_load_fpr_D(dc, rs1); - cpu_src2_64 = gen_load_fpr_D(dc, rs2); - gen_helper_fcmpne32(cpu_dst, cpu_src1_64, cpu_src2_64); - gen_store_gpr(dc, rd, cpu_dst); - break; - case 0x028: /* VIS I fcmpgt16 */ - CHECK_FPU_FEATURE(dc, VIS1); - cpu_src1_64 = gen_load_fpr_D(dc, rs1); - cpu_src2_64 = gen_load_fpr_D(dc, rs2); - gen_helper_fcmpgt16(cpu_dst, cpu_src1_64, cpu_src2_64); - gen_store_gpr(dc, rd, cpu_dst); - break; - case 0x02a: /* VIS I fcmpeq16 */ - CHECK_FPU_FEATURE(dc, VIS1); - cpu_src1_64 = gen_load_fpr_D(dc, rs1); - cpu_src2_64 = gen_load_fpr_D(dc, rs2); - gen_helper_fcmpeq16(cpu_dst, cpu_src1_64, cpu_src2_64); - gen_store_gpr(dc, rd, cpu_dst); - break; - case 0x02c: /* VIS I fcmpgt32 */ - CHECK_FPU_FEATURE(dc, VIS1); - cpu_src1_64 = gen_load_fpr_D(dc, rs1); - cpu_src2_64 = gen_load_fpr_D(dc, rs2); - gen_helper_fcmpgt32(cpu_dst, cpu_src1_64, cpu_src2_64); - gen_store_gpr(dc, rd, cpu_dst); - break; - case 0x02e: /* VIS I fcmpeq32 */ - CHECK_FPU_FEATURE(dc, VIS1); - cpu_src1_64 = gen_load_fpr_D(dc, rs1); - cpu_src2_64 = gen_load_fpr_D(dc, rs2); - gen_helper_fcmpeq32(cpu_dst, cpu_src1_64, cpu_src2_64); - gen_store_gpr(dc, rd, cpu_dst); - break; - case 0x031: /* VIS I fmul8x16 */ - CHECK_FPU_FEATURE(dc, VIS1); - gen_ne_fop_DDD(dc, rd, rs1, rs2, gen_helper_fmul8x16); - break; - case 0x033: /* VIS I fmul8x16au */ - CHECK_FPU_FEATURE(dc, VIS1); - gen_ne_fop_DDD(dc, rd, rs1, rs2, gen_helper_fmul8x16au); - break; - case 0x035: /* VIS I fmul8x16al */ - CHECK_FPU_FEATURE(dc, VIS1); - gen_ne_fop_DDD(dc, rd, rs1, rs2, gen_helper_fmul8x16al); - break; - case 0x036: /* VIS I fmul8sux16 */ - CHECK_FPU_FEATURE(dc, VIS1); - gen_ne_fop_DDD(dc, rd, rs1, rs2, gen_helper_fmul8sux16); - break; - case 0x037: /* VIS I fmul8ulx16 */ - CHECK_FPU_FEATURE(dc, VIS1); - gen_ne_fop_DDD(dc, rd, rs1, rs2, gen_helper_fmul8ulx16); - break; - case 0x038: /* VIS I fmuld8sux16 */ - CHECK_FPU_FEATURE(dc, VIS1); - gen_ne_fop_DDD(dc, rd, rs1, rs2, gen_helper_fmuld8sux16); - break; - case 0x039: /* VIS I fmuld8ulx16 */ - CHECK_FPU_FEATURE(dc, VIS1); - gen_ne_fop_DDD(dc, rd, rs1, rs2, gen_helper_fmuld8ulx16); - break; - case 0x03a: /* VIS I fpack32 */ - CHECK_FPU_FEATURE(dc, VIS1); - gen_gsr_fop_DDD(dc, rd, rs1, rs2, gen_helper_fpack32); - break; - case 0x03b: /* VIS I fpack16 */ - CHECK_FPU_FEATURE(dc, VIS1); - cpu_src1_64 = gen_load_fpr_D(dc, rs2); - cpu_dst_32 = gen_dest_fpr_F(dc); - gen_helper_fpack16(cpu_dst_32, cpu_gsr, cpu_src1_64); - gen_store_fpr_F(dc, rd, cpu_dst_32); - break; - case 0x03d: /* VIS I fpackfix */ - CHECK_FPU_FEATURE(dc, VIS1); - cpu_src1_64 = gen_load_fpr_D(dc, rs2); - cpu_dst_32 = gen_dest_fpr_F(dc); - gen_helper_fpackfix(cpu_dst_32, cpu_gsr, cpu_src1_64); - gen_store_fpr_F(dc, rd, cpu_dst_32); - break; - case 0x03e: /* VIS I pdist */ - CHECK_FPU_FEATURE(dc, VIS1); - gen_ne_fop_DDDD(dc, rd, rs1, rs2, gen_helper_pdist); - break; - case 0x048: /* VIS I faligndata */ - CHECK_FPU_FEATURE(dc, VIS1); - gen_gsr_fop_DDD(dc, rd, rs1, rs2, gen_faligndata); - break; - case 0x04b: /* VIS I fpmerge */ - CHECK_FPU_FEATURE(dc, VIS1); - gen_ne_fop_DDD(dc, rd, rs1, rs2, gen_helper_fpmerge); - break; - case 0x04c: /* VIS II bshuffle */ - CHECK_FPU_FEATURE(dc, VIS2); - gen_gsr_fop_DDD(dc, rd, rs1, rs2, gen_helper_bshuffle); - break; - case 0x04d: /* VIS I fexpand */ - CHECK_FPU_FEATURE(dc, VIS1); - gen_ne_fop_DDD(dc, rd, rs1, rs2, gen_helper_fexpand); - break; - case 0x050: /* VIS I fpadd16 */ - CHECK_FPU_FEATURE(dc, VIS1); - gen_ne_fop_DDD(dc, rd, rs1, rs2, gen_helper_fpadd16); - break; - case 0x051: /* VIS I fpadd16s */ - CHECK_FPU_FEATURE(dc, VIS1); - gen_ne_fop_FFF(dc, rd, rs1, rs2, gen_helper_fpadd16s); - break; - case 0x052: /* VIS I fpadd32 */ - CHECK_FPU_FEATURE(dc, VIS1); - gen_ne_fop_DDD(dc, rd, rs1, rs2, gen_helper_fpadd32); - break; - case 0x053: /* VIS I fpadd32s */ - CHECK_FPU_FEATURE(dc, VIS1); - gen_ne_fop_FFF(dc, rd, rs1, rs2, tcg_gen_add_i32); - break; - case 0x054: /* VIS I fpsub16 */ - CHECK_FPU_FEATURE(dc, VIS1); - gen_ne_fop_DDD(dc, rd, rs1, rs2, gen_helper_fpsub16); - break; - case 0x055: /* VIS I fpsub16s */ - CHECK_FPU_FEATURE(dc, VIS1); - gen_ne_fop_FFF(dc, rd, rs1, rs2, gen_helper_fpsub16s); - break; - case 0x056: /* VIS I fpsub32 */ - CHECK_FPU_FEATURE(dc, VIS1); - gen_ne_fop_DDD(dc, rd, rs1, rs2, gen_helper_fpsub32); - break; - case 0x057: /* VIS I fpsub32s */ - CHECK_FPU_FEATURE(dc, VIS1); - gen_ne_fop_FFF(dc, rd, rs1, rs2, tcg_gen_sub_i32); - break; - case 0x060: /* VIS I fzero */ - CHECK_FPU_FEATURE(dc, VIS1); - cpu_dst_64 = gen_dest_fpr_D(dc, rd); - tcg_gen_movi_i64(cpu_dst_64, 0); - gen_store_fpr_D(dc, rd, cpu_dst_64); - break; - case 0x061: /* VIS I fzeros */ - CHECK_FPU_FEATURE(dc, VIS1); - cpu_dst_32 = gen_dest_fpr_F(dc); - tcg_gen_movi_i32(cpu_dst_32, 0); - gen_store_fpr_F(dc, rd, cpu_dst_32); - break; - case 0x062: /* VIS I fnor */ - CHECK_FPU_FEATURE(dc, VIS1); - gen_ne_fop_DDD(dc, rd, rs1, rs2, tcg_gen_nor_i64); - break; - case 0x063: /* VIS I fnors */ - CHECK_FPU_FEATURE(dc, VIS1); - gen_ne_fop_FFF(dc, rd, rs1, rs2, tcg_gen_nor_i32); - break; - case 0x064: /* VIS I fandnot2 */ - CHECK_FPU_FEATURE(dc, VIS1); - gen_ne_fop_DDD(dc, rd, rs1, rs2, tcg_gen_andc_i64); - break; - case 0x065: /* VIS I fandnot2s */ - CHECK_FPU_FEATURE(dc, VIS1); - gen_ne_fop_FFF(dc, rd, rs1, rs2, tcg_gen_andc_i32); - break; - case 0x066: /* VIS I fnot2 */ - CHECK_FPU_FEATURE(dc, VIS1); - gen_ne_fop_DD(dc, rd, rs2, tcg_gen_not_i64); - break; - case 0x067: /* VIS I fnot2s */ - CHECK_FPU_FEATURE(dc, VIS1); - gen_ne_fop_FF(dc, rd, rs2, tcg_gen_not_i32); - break; - case 0x068: /* VIS I fandnot1 */ - CHECK_FPU_FEATURE(dc, VIS1); - gen_ne_fop_DDD(dc, rd, rs2, rs1, tcg_gen_andc_i64); - break; - case 0x069: /* VIS I fandnot1s */ - CHECK_FPU_FEATURE(dc, VIS1); - gen_ne_fop_FFF(dc, rd, rs2, rs1, tcg_gen_andc_i32); - break; - case 0x06a: /* VIS I fnot1 */ - CHECK_FPU_FEATURE(dc, VIS1); - gen_ne_fop_DD(dc, rd, rs1, tcg_gen_not_i64); - break; - case 0x06b: /* VIS I fnot1s */ - CHECK_FPU_FEATURE(dc, VIS1); - gen_ne_fop_FF(dc, rd, rs1, tcg_gen_not_i32); - break; - case 0x06c: /* VIS I fxor */ - CHECK_FPU_FEATURE(dc, VIS1); - gen_ne_fop_DDD(dc, rd, rs1, rs2, tcg_gen_xor_i64); - break; - case 0x06d: /* VIS I fxors */ - CHECK_FPU_FEATURE(dc, VIS1); - gen_ne_fop_FFF(dc, rd, rs1, rs2, tcg_gen_xor_i32); - break; - case 0x06e: /* VIS I fnand */ - CHECK_FPU_FEATURE(dc, VIS1); - gen_ne_fop_DDD(dc, rd, rs1, rs2, tcg_gen_nand_i64); - break; - case 0x06f: /* VIS I fnands */ - CHECK_FPU_FEATURE(dc, VIS1); - gen_ne_fop_FFF(dc, rd, rs1, rs2, tcg_gen_nand_i32); - break; - case 0x070: /* VIS I fand */ - CHECK_FPU_FEATURE(dc, VIS1); - gen_ne_fop_DDD(dc, rd, rs1, rs2, tcg_gen_and_i64); - break; - case 0x071: /* VIS I fands */ - CHECK_FPU_FEATURE(dc, VIS1); - gen_ne_fop_FFF(dc, rd, rs1, rs2, tcg_gen_and_i32); - break; - case 0x072: /* VIS I fxnor */ - CHECK_FPU_FEATURE(dc, VIS1); - gen_ne_fop_DDD(dc, rd, rs1, rs2, tcg_gen_eqv_i64); - break; - case 0x073: /* VIS I fxnors */ - CHECK_FPU_FEATURE(dc, VIS1); - gen_ne_fop_FFF(dc, rd, rs1, rs2, tcg_gen_eqv_i32); - break; - case 0x074: /* VIS I fsrc1 */ - CHECK_FPU_FEATURE(dc, VIS1); - cpu_src1_64 = gen_load_fpr_D(dc, rs1); - gen_store_fpr_D(dc, rd, cpu_src1_64); - break; - case 0x075: /* VIS I fsrc1s */ - CHECK_FPU_FEATURE(dc, VIS1); - cpu_src1_32 = gen_load_fpr_F(dc, rs1); - gen_store_fpr_F(dc, rd, cpu_src1_32); - break; - case 0x076: /* VIS I fornot2 */ - CHECK_FPU_FEATURE(dc, VIS1); - gen_ne_fop_DDD(dc, rd, rs1, rs2, tcg_gen_orc_i64); - break; - case 0x077: /* VIS I fornot2s */ - CHECK_FPU_FEATURE(dc, VIS1); - gen_ne_fop_FFF(dc, rd, rs1, rs2, tcg_gen_orc_i32); - break; - case 0x078: /* VIS I fsrc2 */ - CHECK_FPU_FEATURE(dc, VIS1); - cpu_src1_64 = gen_load_fpr_D(dc, rs2); - gen_store_fpr_D(dc, rd, cpu_src1_64); - break; - case 0x079: /* VIS I fsrc2s */ - CHECK_FPU_FEATURE(dc, VIS1); - cpu_src1_32 = gen_load_fpr_F(dc, rs2); - gen_store_fpr_F(dc, rd, cpu_src1_32); - break; - case 0x07a: /* VIS I fornot1 */ - CHECK_FPU_FEATURE(dc, VIS1); - gen_ne_fop_DDD(dc, rd, rs2, rs1, tcg_gen_orc_i64); - break; - case 0x07b: /* VIS I fornot1s */ - CHECK_FPU_FEATURE(dc, VIS1); - gen_ne_fop_FFF(dc, rd, rs2, rs1, tcg_gen_orc_i32); - break; - case 0x07c: /* VIS I for */ - CHECK_FPU_FEATURE(dc, VIS1); - gen_ne_fop_DDD(dc, rd, rs1, rs2, tcg_gen_or_i64); - break; - case 0x07d: /* VIS I fors */ - CHECK_FPU_FEATURE(dc, VIS1); - gen_ne_fop_FFF(dc, rd, rs1, rs2, tcg_gen_or_i32); - break; - case 0x07e: /* VIS I fone */ - CHECK_FPU_FEATURE(dc, VIS1); - cpu_dst_64 = gen_dest_fpr_D(dc, rd); - tcg_gen_movi_i64(cpu_dst_64, -1); - gen_store_fpr_D(dc, rd, cpu_dst_64); - break; - case 0x07f: /* VIS I fones */ - CHECK_FPU_FEATURE(dc, VIS1); - cpu_dst_32 = gen_dest_fpr_F(dc); - tcg_gen_movi_i32(cpu_dst_32, -1); - gen_store_fpr_F(dc, rd, cpu_dst_32); - break; - case 0x080: /* VIS I shutdown */ - case 0x081: /* VIS II siam */ - // XXX - goto illegal_insn; - default: - goto illegal_insn; - } -#else - goto ncp_insn; -#endif - } else if (xop == 0x37) { /* V8 CPop2, V9 impdep2 */ -#ifdef TARGET_SPARC64 - goto illegal_insn; -#else - goto ncp_insn; -#endif -#ifdef TARGET_SPARC64 - } else if (xop == 0x39) { /* V9 return */ - TCGv_i32 r_const; - - save_state(dc); - cpu_src1 = get_src1(dc, insn); - cpu_tmp0 = get_temp_tl(dc); - if (IS_IMM) { /* immediate */ - simm = GET_FIELDs(insn, 19, 31); - tcg_gen_addi_tl(cpu_tmp0, cpu_src1, simm); - } else { /* register */ - rs2 = GET_FIELD(insn, 27, 31); - if (rs2) { - cpu_src2 = gen_load_gpr(dc, rs2); - tcg_gen_add_tl(cpu_tmp0, cpu_src1, cpu_src2); - } else { - tcg_gen_mov_tl(cpu_tmp0, cpu_src1); - } - } - gen_helper_restore(cpu_env); - gen_mov_pc_npc(dc); - r_const = tcg_const_i32(3); - gen_helper_check_align(cpu_env, cpu_tmp0, r_const); - tcg_temp_free_i32(r_const); - tcg_gen_mov_tl(cpu_npc, cpu_tmp0); - dc->npc = DYNAMIC_PC; - goto jmp_insn; -#endif - } else { - cpu_src1 = get_src1(dc, insn); - cpu_tmp0 = get_temp_tl(dc); - if (IS_IMM) { /* immediate */ - simm = GET_FIELDs(insn, 19, 31); - tcg_gen_addi_tl(cpu_tmp0, cpu_src1, simm); - } else { /* register */ - rs2 = GET_FIELD(insn, 27, 31); - if (rs2) { - cpu_src2 = gen_load_gpr(dc, rs2); - tcg_gen_add_tl(cpu_tmp0, cpu_src1, cpu_src2); - } else { - tcg_gen_mov_tl(cpu_tmp0, cpu_src1); - } - } - switch (xop) { - case 0x38: /* jmpl */ - { - TCGv t; - TCGv_i32 r_const; - - t = gen_dest_gpr(dc, rd); - tcg_gen_movi_tl(t, dc->pc); - gen_store_gpr(dc, rd, t); - gen_mov_pc_npc(dc); - r_const = tcg_const_i32(3); - gen_helper_check_align(cpu_env, cpu_tmp0, r_const); - tcg_temp_free_i32(r_const); - gen_address_mask(dc, cpu_tmp0); - tcg_gen_mov_tl(cpu_npc, cpu_tmp0); - dc->npc = DYNAMIC_PC; - } - goto jmp_insn; -#if !defined(CONFIG_USER_ONLY) && !defined(TARGET_SPARC64) - case 0x39: /* rett, V9 return */ - { - TCGv_i32 r_const; - - if (!supervisor(dc)) - goto priv_insn; - gen_mov_pc_npc(dc); - r_const = tcg_const_i32(3); - gen_helper_check_align(cpu_env, cpu_tmp0, r_const); - tcg_temp_free_i32(r_const); - tcg_gen_mov_tl(cpu_npc, cpu_tmp0); - dc->npc = DYNAMIC_PC; - gen_helper_rett(cpu_env); - } - goto jmp_insn; -#endif - case 0x3b: /* flush */ - if (!((dc)->def->features & CPU_FEATURE_FLUSH)) - goto unimp_flush; - /* nop */ - break; - case 0x3c: /* save */ - save_state(dc); - gen_helper_save(cpu_env); - gen_store_gpr(dc, rd, cpu_tmp0); - break; - case 0x3d: /* restore */ - save_state(dc); - gen_helper_restore(cpu_env); - gen_store_gpr(dc, rd, cpu_tmp0); - break; -#if !defined(CONFIG_USER_ONLY) && defined(TARGET_SPARC64) - case 0x3e: /* V9 done/retry */ - { - switch (rd) { - case 0: - if (!supervisor(dc)) - goto priv_insn; - dc->npc = DYNAMIC_PC; - dc->pc = DYNAMIC_PC; - gen_helper_done(cpu_env); - goto jmp_insn; - case 1: - if (!supervisor(dc)) - goto priv_insn; - dc->npc = DYNAMIC_PC; - dc->pc = DYNAMIC_PC; - gen_helper_retry(cpu_env); - goto jmp_insn; - default: - goto illegal_insn; - } - } - break; -#endif - default: - goto illegal_insn; - } - } - break; - } - break; - case 3: /* load/store instructions */ - { - unsigned int xop = GET_FIELD(insn, 7, 12); - /* ??? gen_address_mask prevents us from using a source - register directly. Always generate a temporary. */ - TCGv cpu_addr = get_temp_tl(dc); - - tcg_gen_mov_tl(cpu_addr, get_src1(dc, insn)); - if (xop == 0x3c || xop == 0x3e) { - /* V9 casa/casxa : no offset */ - } else if (IS_IMM) { /* immediate */ - simm = GET_FIELDs(insn, 19, 31); - if (simm != 0) { - tcg_gen_addi_tl(cpu_addr, cpu_addr, simm); - } - } else { /* register */ - rs2 = GET_FIELD(insn, 27, 31); - if (rs2 != 0) { - tcg_gen_add_tl(cpu_addr, cpu_addr, gen_load_gpr(dc, rs2)); - } - } - if (xop < 4 || (xop > 7 && xop < 0x14 && xop != 0x0e) || - (xop > 0x17 && xop <= 0x1d ) || - (xop > 0x2c && xop <= 0x33) || xop == 0x1f || xop == 0x3d) { - TCGv cpu_val = gen_dest_gpr(dc, rd); - - switch (xop) { - case 0x0: /* ld, V9 lduw, load unsigned word */ - gen_address_mask(dc, cpu_addr); - tcg_gen_qemu_ld32u(cpu_val, cpu_addr, dc->mem_idx); - break; - case 0x1: /* ldub, load unsigned byte */ - gen_address_mask(dc, cpu_addr); - tcg_gen_qemu_ld8u(cpu_val, cpu_addr, dc->mem_idx); - break; - case 0x2: /* lduh, load unsigned halfword */ - gen_address_mask(dc, cpu_addr); - tcg_gen_qemu_ld16u(cpu_val, cpu_addr, dc->mem_idx); - break; - case 0x3: /* ldd, load double word */ - if (rd & 1) - goto illegal_insn; - else { - TCGv_i32 r_const; - TCGv_i64 t64; - - save_state(dc); - r_const = tcg_const_i32(7); - /* XXX remove alignment check */ - gen_helper_check_align(cpu_env, cpu_addr, r_const); - tcg_temp_free_i32(r_const); - gen_address_mask(dc, cpu_addr); - t64 = tcg_temp_new_i64(); - tcg_gen_qemu_ld64(t64, cpu_addr, dc->mem_idx); - tcg_gen_trunc_i64_tl(cpu_val, t64); - tcg_gen_ext32u_tl(cpu_val, cpu_val); - gen_store_gpr(dc, rd + 1, cpu_val); - tcg_gen_shri_i64(t64, t64, 32); - tcg_gen_trunc_i64_tl(cpu_val, t64); - tcg_temp_free_i64(t64); - tcg_gen_ext32u_tl(cpu_val, cpu_val); - } - break; - case 0x9: /* ldsb, load signed byte */ - gen_address_mask(dc, cpu_addr); - tcg_gen_qemu_ld8s(cpu_val, cpu_addr, dc->mem_idx); - break; - case 0xa: /* ldsh, load signed halfword */ - gen_address_mask(dc, cpu_addr); - tcg_gen_qemu_ld16s(cpu_val, cpu_addr, dc->mem_idx); - break; - case 0xd: /* ldstub -- XXX: should be atomically */ - { - TCGv r_const; - - gen_address_mask(dc, cpu_addr); - tcg_gen_qemu_ld8u(cpu_val, cpu_addr, dc->mem_idx); - r_const = tcg_const_tl(0xff); - tcg_gen_qemu_st8(r_const, cpu_addr, dc->mem_idx); - tcg_temp_free(r_const); - } - break; - case 0x0f: - /* swap, swap register with memory. Also atomically */ - { - TCGv t0 = get_temp_tl(dc); - CHECK_IU_FEATURE(dc, SWAP); - cpu_src1 = gen_load_gpr(dc, rd); - gen_address_mask(dc, cpu_addr); - tcg_gen_qemu_ld32u(t0, cpu_addr, dc->mem_idx); - tcg_gen_qemu_st32(cpu_src1, cpu_addr, dc->mem_idx); - tcg_gen_mov_tl(cpu_val, t0); - } - break; -#if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64) - case 0x10: /* lda, V9 lduwa, load word alternate */ -#ifndef TARGET_SPARC64 - if (IS_IMM) - goto illegal_insn; - if (!supervisor(dc)) - goto priv_insn; -#endif - save_state(dc); - gen_ld_asi(cpu_val, cpu_addr, insn, 4, 0); - break; - case 0x11: /* lduba, load unsigned byte alternate */ -#ifndef TARGET_SPARC64 - if (IS_IMM) - goto illegal_insn; - if (!supervisor(dc)) - goto priv_insn; -#endif - save_state(dc); - gen_ld_asi(cpu_val, cpu_addr, insn, 1, 0); - break; - case 0x12: /* lduha, load unsigned halfword alternate */ -#ifndef TARGET_SPARC64 - if (IS_IMM) - goto illegal_insn; - if (!supervisor(dc)) - goto priv_insn; -#endif - save_state(dc); - gen_ld_asi(cpu_val, cpu_addr, insn, 2, 0); - break; - case 0x13: /* ldda, load double word alternate */ -#ifndef TARGET_SPARC64 - if (IS_IMM) - goto illegal_insn; - if (!supervisor(dc)) - goto priv_insn; -#endif - if (rd & 1) - goto illegal_insn; - save_state(dc); - gen_ldda_asi(dc, cpu_val, cpu_addr, insn, rd); - goto skip_move; - case 0x19: /* ldsba, load signed byte alternate */ -#ifndef TARGET_SPARC64 - if (IS_IMM) - goto illegal_insn; - if (!supervisor(dc)) - goto priv_insn; -#endif - save_state(dc); - gen_ld_asi(cpu_val, cpu_addr, insn, 1, 1); - break; - case 0x1a: /* ldsha, load signed halfword alternate */ -#ifndef TARGET_SPARC64 - if (IS_IMM) - goto illegal_insn; - if (!supervisor(dc)) - goto priv_insn; -#endif - save_state(dc); - gen_ld_asi(cpu_val, cpu_addr, insn, 2, 1); - break; - case 0x1d: /* ldstuba -- XXX: should be atomically */ -#ifndef TARGET_SPARC64 - if (IS_IMM) - goto illegal_insn; - if (!supervisor(dc)) - goto priv_insn; -#endif - save_state(dc); - gen_ldstub_asi(cpu_val, cpu_addr, insn); - break; - case 0x1f: /* swapa, swap reg with alt. memory. Also - atomically */ - CHECK_IU_FEATURE(dc, SWAP); -#ifndef TARGET_SPARC64 - if (IS_IMM) - goto illegal_insn; - if (!supervisor(dc)) - goto priv_insn; -#endif - save_state(dc); - cpu_src1 = gen_load_gpr(dc, rd); - gen_swap_asi(cpu_val, cpu_src1, cpu_addr, insn); - break; - -#ifndef TARGET_SPARC64 - case 0x30: /* ldc */ - case 0x31: /* ldcsr */ - case 0x33: /* lddc */ - goto ncp_insn; -#endif -#endif -#ifdef TARGET_SPARC64 - case 0x08: /* V9 ldsw */ - gen_address_mask(dc, cpu_addr); - tcg_gen_qemu_ld32s(cpu_val, cpu_addr, dc->mem_idx); - break; - case 0x0b: /* V9 ldx */ - gen_address_mask(dc, cpu_addr); - tcg_gen_qemu_ld64(cpu_val, cpu_addr, dc->mem_idx); - break; - case 0x18: /* V9 ldswa */ - save_state(dc); - gen_ld_asi(cpu_val, cpu_addr, insn, 4, 1); - break; - case 0x1b: /* V9 ldxa */ - save_state(dc); - gen_ld_asi(cpu_val, cpu_addr, insn, 8, 0); - break; - case 0x2d: /* V9 prefetch, no effect */ - goto skip_move; - case 0x30: /* V9 ldfa */ - if (gen_trap_ifnofpu(dc)) { - goto jmp_insn; - } - save_state(dc); - gen_ldf_asi(cpu_addr, insn, 4, rd); - gen_update_fprs_dirty(rd); - goto skip_move; - case 0x33: /* V9 lddfa */ - if (gen_trap_ifnofpu(dc)) { - goto jmp_insn; - } - save_state(dc); - gen_ldf_asi(cpu_addr, insn, 8, DFPREG(rd)); - gen_update_fprs_dirty(DFPREG(rd)); - goto skip_move; - case 0x3d: /* V9 prefetcha, no effect */ - goto skip_move; - case 0x32: /* V9 ldqfa */ - CHECK_FPU_FEATURE(dc, FLOAT128); - if (gen_trap_ifnofpu(dc)) { - goto jmp_insn; - } - save_state(dc); - gen_ldf_asi(cpu_addr, insn, 16, QFPREG(rd)); - gen_update_fprs_dirty(QFPREG(rd)); - goto skip_move; -#endif - default: - goto illegal_insn; - } - gen_store_gpr(dc, rd, cpu_val); -#if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64) - skip_move: ; -#endif - } else if (xop >= 0x20 && xop < 0x24) { - TCGv t0; - - if (gen_trap_ifnofpu(dc)) { - goto jmp_insn; - } - save_state(dc); - switch (xop) { - case 0x20: /* ldf, load fpreg */ - gen_address_mask(dc, cpu_addr); - t0 = get_temp_tl(dc); - tcg_gen_qemu_ld32u(t0, cpu_addr, dc->mem_idx); - cpu_dst_32 = gen_dest_fpr_F(dc); - tcg_gen_trunc_tl_i32(cpu_dst_32, t0); - gen_store_fpr_F(dc, rd, cpu_dst_32); - break; - case 0x21: /* ldfsr, V9 ldxfsr */ -#ifdef TARGET_SPARC64 - gen_address_mask(dc, cpu_addr); - if (rd == 1) { - TCGv_i64 t64 = tcg_temp_new_i64(); - tcg_gen_qemu_ld64(t64, cpu_addr, dc->mem_idx); - gen_helper_ldxfsr(cpu_env, t64); - tcg_temp_free_i64(t64); - break; - } -#endif - cpu_dst_32 = get_temp_i32(dc); - t0 = get_temp_tl(dc); - tcg_gen_qemu_ld32u(t0, cpu_addr, dc->mem_idx); - tcg_gen_trunc_tl_i32(cpu_dst_32, t0); - gen_helper_ldfsr(cpu_env, cpu_dst_32); - break; - case 0x22: /* ldqf, load quad fpreg */ - { - TCGv_i32 r_const; - - CHECK_FPU_FEATURE(dc, FLOAT128); - r_const = tcg_const_i32(dc->mem_idx); - gen_address_mask(dc, cpu_addr); - gen_helper_ldqf(cpu_env, cpu_addr, r_const); - tcg_temp_free_i32(r_const); - gen_op_store_QT0_fpr(QFPREG(rd)); - gen_update_fprs_dirty(QFPREG(rd)); - } - break; - case 0x23: /* lddf, load double fpreg */ - gen_address_mask(dc, cpu_addr); - cpu_dst_64 = gen_dest_fpr_D(dc, rd); - tcg_gen_qemu_ld64(cpu_dst_64, cpu_addr, dc->mem_idx); - gen_store_fpr_D(dc, rd, cpu_dst_64); - break; - default: - goto illegal_insn; - } - } else if (xop < 8 || (xop >= 0x14 && xop < 0x18) || - xop == 0xe || xop == 0x1e) { - TCGv cpu_val = gen_load_gpr(dc, rd); - - switch (xop) { - case 0x4: /* st, store word */ - gen_address_mask(dc, cpu_addr); - tcg_gen_qemu_st32(cpu_val, cpu_addr, dc->mem_idx); - break; - case 0x5: /* stb, store byte */ - gen_address_mask(dc, cpu_addr); - tcg_gen_qemu_st8(cpu_val, cpu_addr, dc->mem_idx); - break; - case 0x6: /* sth, store halfword */ - gen_address_mask(dc, cpu_addr); - tcg_gen_qemu_st16(cpu_val, cpu_addr, dc->mem_idx); - break; - case 0x7: /* std, store double word */ - if (rd & 1) - goto illegal_insn; - else { - TCGv_i32 r_const; - TCGv_i64 t64; - TCGv lo; - - save_state(dc); - gen_address_mask(dc, cpu_addr); - r_const = tcg_const_i32(7); - /* XXX remove alignment check */ - gen_helper_check_align(cpu_env, cpu_addr, r_const); - tcg_temp_free_i32(r_const); - lo = gen_load_gpr(dc, rd + 1); - - t64 = tcg_temp_new_i64(); - tcg_gen_concat_tl_i64(t64, lo, cpu_val); - tcg_gen_qemu_st64(t64, cpu_addr, dc->mem_idx); - tcg_temp_free_i64(t64); - } - break; -#if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64) - case 0x14: /* sta, V9 stwa, store word alternate */ -#ifndef TARGET_SPARC64 - if (IS_IMM) - goto illegal_insn; - if (!supervisor(dc)) - goto priv_insn; -#endif - save_state(dc); - gen_st_asi(cpu_val, cpu_addr, insn, 4); - dc->npc = DYNAMIC_PC; - break; - case 0x15: /* stba, store byte alternate */ -#ifndef TARGET_SPARC64 - if (IS_IMM) - goto illegal_insn; - if (!supervisor(dc)) - goto priv_insn; -#endif - save_state(dc); - gen_st_asi(cpu_val, cpu_addr, insn, 1); - dc->npc = DYNAMIC_PC; - break; - case 0x16: /* stha, store halfword alternate */ -#ifndef TARGET_SPARC64 - if (IS_IMM) - goto illegal_insn; - if (!supervisor(dc)) - goto priv_insn; -#endif - save_state(dc); - gen_st_asi(cpu_val, cpu_addr, insn, 2); - dc->npc = DYNAMIC_PC; - break; - case 0x17: /* stda, store double word alternate */ -#ifndef TARGET_SPARC64 - if (IS_IMM) - goto illegal_insn; - if (!supervisor(dc)) - goto priv_insn; -#endif - if (rd & 1) - goto illegal_insn; - else { - save_state(dc); - gen_stda_asi(dc, cpu_val, cpu_addr, insn, rd); - } - break; -#endif -#ifdef TARGET_SPARC64 - case 0x0e: /* V9 stx */ - gen_address_mask(dc, cpu_addr); - tcg_gen_qemu_st64(cpu_val, cpu_addr, dc->mem_idx); - break; - case 0x1e: /* V9 stxa */ - save_state(dc); - gen_st_asi(cpu_val, cpu_addr, insn, 8); - dc->npc = DYNAMIC_PC; - break; -#endif - default: - goto illegal_insn; - } - } else if (xop > 0x23 && xop < 0x28) { - if (gen_trap_ifnofpu(dc)) { - goto jmp_insn; - } - save_state(dc); - switch (xop) { - case 0x24: /* stf, store fpreg */ - { - TCGv t = get_temp_tl(dc); - gen_address_mask(dc, cpu_addr); - cpu_src1_32 = gen_load_fpr_F(dc, rd); - tcg_gen_ext_i32_tl(t, cpu_src1_32); - tcg_gen_qemu_st32(t, cpu_addr, dc->mem_idx); - } - break; - case 0x25: /* stfsr, V9 stxfsr */ - { - TCGv t = get_temp_tl(dc); - - tcg_gen_ld_tl(t, cpu_env, offsetof(CPUSPARCState, fsr)); -#ifdef TARGET_SPARC64 - gen_address_mask(dc, cpu_addr); - if (rd == 1) { - tcg_gen_qemu_st64(t, cpu_addr, dc->mem_idx); - break; - } -#endif - tcg_gen_qemu_st32(t, cpu_addr, dc->mem_idx); - } - break; - case 0x26: -#ifdef TARGET_SPARC64 - /* V9 stqf, store quad fpreg */ - { - TCGv_i32 r_const; - - CHECK_FPU_FEATURE(dc, FLOAT128); - gen_op_load_fpr_QT0(QFPREG(rd)); - r_const = tcg_const_i32(dc->mem_idx); - gen_address_mask(dc, cpu_addr); - gen_helper_stqf(cpu_env, cpu_addr, r_const); - tcg_temp_free_i32(r_const); - } - break; -#else /* !TARGET_SPARC64 */ - /* stdfq, store floating point queue */ -#if defined(CONFIG_USER_ONLY) - goto illegal_insn; -#else - if (!supervisor(dc)) - goto priv_insn; - if (gen_trap_ifnofpu(dc)) { - goto jmp_insn; - } - goto nfq_insn; -#endif -#endif - case 0x27: /* stdf, store double fpreg */ - gen_address_mask(dc, cpu_addr); - cpu_src1_64 = gen_load_fpr_D(dc, rd); - tcg_gen_qemu_st64(cpu_src1_64, cpu_addr, dc->mem_idx); - break; - default: - goto illegal_insn; - } - } else if (xop > 0x33 && xop < 0x3f) { - save_state(dc); - switch (xop) { -#ifdef TARGET_SPARC64 - case 0x34: /* V9 stfa */ - if (gen_trap_ifnofpu(dc)) { - goto jmp_insn; - } - gen_stf_asi(cpu_addr, insn, 4, rd); - break; - case 0x36: /* V9 stqfa */ - { - TCGv_i32 r_const; - - CHECK_FPU_FEATURE(dc, FLOAT128); - if (gen_trap_ifnofpu(dc)) { - goto jmp_insn; - } - r_const = tcg_const_i32(7); - gen_helper_check_align(cpu_env, cpu_addr, r_const); - tcg_temp_free_i32(r_const); - gen_stf_asi(cpu_addr, insn, 16, QFPREG(rd)); - } - break; - case 0x37: /* V9 stdfa */ - if (gen_trap_ifnofpu(dc)) { - goto jmp_insn; - } - gen_stf_asi(cpu_addr, insn, 8, DFPREG(rd)); - break; - case 0x3e: /* V9 casxa */ - rs2 = GET_FIELD(insn, 27, 31); - cpu_src2 = gen_load_gpr(dc, rs2); - gen_casx_asi(dc, cpu_addr, cpu_src2, insn, rd); - break; -#else - case 0x34: /* stc */ - case 0x35: /* stcsr */ - case 0x36: /* stdcq */ - case 0x37: /* stdc */ - goto ncp_insn; -#endif -#if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64) - case 0x3c: /* V9 or LEON3 casa */ -#ifndef TARGET_SPARC64 - CHECK_IU_FEATURE(dc, CASA); - if (IS_IMM) { - goto illegal_insn; - } - /* LEON3 allows CASA from user space with ASI 0xa */ - if ((GET_FIELD(insn, 19, 26) != 0xa) && !supervisor(dc)) { - goto priv_insn; - } -#endif - rs2 = GET_FIELD(insn, 27, 31); - cpu_src2 = gen_load_gpr(dc, rs2); - gen_cas_asi(dc, cpu_addr, cpu_src2, insn, rd); - break; -#endif - default: - goto illegal_insn; - } - } else { - goto illegal_insn; - } - } - break; - } - /* default case for non jump instructions */ - if (dc->npc == DYNAMIC_PC) { - dc->pc = DYNAMIC_PC; - gen_op_next_insn(); - } else if (dc->npc == JUMP_PC) { - /* we can do a static jump */ - gen_branch2(dc, dc->jump_pc[0], dc->jump_pc[1], cpu_cond); - dc->is_br = 1; - } else { - dc->pc = dc->npc; - dc->npc = dc->npc + 4; - } - jmp_insn: - goto egress; - illegal_insn: - { - TCGv_i32 r_const; - - save_state(dc); - r_const = tcg_const_i32(TT_ILL_INSN); - gen_helper_raise_exception(cpu_env, r_const); - tcg_temp_free_i32(r_const); - dc->is_br = 1; - } - goto egress; - unimp_flush: - { - TCGv_i32 r_const; - - save_state(dc); - r_const = tcg_const_i32(TT_UNIMP_FLUSH); - gen_helper_raise_exception(cpu_env, r_const); - tcg_temp_free_i32(r_const); - dc->is_br = 1; - } - goto egress; -#if !defined(CONFIG_USER_ONLY) - priv_insn: - { - TCGv_i32 r_const; - - save_state(dc); - r_const = tcg_const_i32(TT_PRIV_INSN); - gen_helper_raise_exception(cpu_env, r_const); - tcg_temp_free_i32(r_const); - dc->is_br = 1; - } - goto egress; -#endif - nfpu_insn: - save_state(dc); - gen_op_fpexception_im(FSR_FTT_UNIMPFPOP); - dc->is_br = 1; - goto egress; -#if !defined(CONFIG_USER_ONLY) && !defined(TARGET_SPARC64) - nfq_insn: - save_state(dc); - gen_op_fpexception_im(FSR_FTT_SEQ_ERROR); - dc->is_br = 1; - goto egress; -#endif -#ifndef TARGET_SPARC64 - ncp_insn: - { - TCGv r_const; - - save_state(dc); - r_const = tcg_const_i32(TT_NCP_INSN); - gen_helper_raise_exception(cpu_env, r_const); - tcg_temp_free(r_const); - dc->is_br = 1; - } - goto egress; -#endif - egress: - if (dc->n_t32 != 0) { - int i; - for (i = dc->n_t32 - 1; i >= 0; --i) { - tcg_temp_free_i32(dc->t32[i]); - } - dc->n_t32 = 0; - } - if (dc->n_ttl != 0) { - int i; - for (i = dc->n_ttl - 1; i >= 0; --i) { - tcg_temp_free(dc->ttl[i]); - } - dc->n_ttl = 0; - } -} - -void gen_intermediate_code(CPUSPARCState * env, TranslationBlock * tb) -{ - SPARCCPU *cpu = sparc_env_get_cpu(env); - CPUState *cs = CPU(cpu); - target_ulong pc_start, last_pc; - DisasContext dc1, *dc = &dc1; - int num_insns; - int max_insns; - unsigned int insn; - - memset(dc, 0, sizeof(DisasContext)); - dc->tb = tb; - pc_start = tb->pc; - dc->pc = pc_start; - last_pc = dc->pc; - dc->npc = (target_ulong) tb->cs_base; - dc->cc_op = CC_OP_DYNAMIC; - dc->mem_idx = cpu_mmu_index(env, false); - dc->def = env->def; - dc->fpu_enabled = tb_fpu_enabled(tb->flags); - dc->address_mask_32bit = tb_am_enabled(tb->flags); - dc->singlestep = (cs->singlestep_enabled || singlestep); - - num_insns = 0; - max_insns = tb->cflags & CF_COUNT_MASK; - if (max_insns == 0) { - max_insns = CF_COUNT_MASK; - } - if (max_insns > TCG_MAX_INSNS) { - max_insns = TCG_MAX_INSNS; - } - - gen_tb_start(tb); - do { - if (dc->npc & JUMP_PC) { - assert(dc->jump_pc[1] == dc->pc + 4); - tcg_gen_insn_start(dc->pc, dc->jump_pc[0] | JUMP_PC); - } else { - tcg_gen_insn_start(dc->pc, dc->npc); - } - num_insns++; - last_pc = dc->pc; - - if (unlikely(cpu_breakpoint_test(cs, dc->pc, BP_ANY))) { - if (dc->pc != pc_start) { - save_state(dc); - } - gen_helper_debug(cpu_env); - tcg_gen_exit_tb(0); - dc->is_br = 1; - goto exit_gen_loop; - } - - if (num_insns == max_insns && (tb->cflags & CF_LAST_IO)) { - gen_io_start(); - } - - insn = cpu_ldl_code(env, dc->pc); - - disas_sparc_insn(dc, insn); - - if (dc->is_br) - break; - /* if the next PC is different, we abort now */ - if (dc->pc != (last_pc + 4)) - break; - /* if we reach a page boundary, we stop generation so that the - PC of a TT_TFAULT exception is always in the right page */ - if ((dc->pc & (TARGET_PAGE_SIZE - 1)) == 0) - break; - /* if single step mode, we generate only one instruction and - generate an exception */ - if (dc->singlestep) { - break; - } - } while (!tcg_op_buf_full() && - (dc->pc - pc_start) < (TARGET_PAGE_SIZE - 32) && - num_insns < max_insns); - - exit_gen_loop: - if (tb->cflags & CF_LAST_IO) { - gen_io_end(); - } - if (!dc->is_br) { - if (dc->pc != DYNAMIC_PC && - (dc->npc != DYNAMIC_PC && dc->npc != JUMP_PC)) { - /* static PC and NPC: we can use direct chaining */ - gen_goto_tb(dc, 0, dc->pc, dc->npc); - } else { - if (dc->pc != DYNAMIC_PC) { - tcg_gen_movi_tl(cpu_pc, dc->pc); - } - save_npc(dc); - tcg_gen_exit_tb(0); - } - } - gen_tb_end(tb, num_insns); - - tb->size = last_pc + 4 - pc_start; - tb->icount = num_insns; - -#ifdef DEBUG_DISAS - if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) { - qemu_log("--------------\n"); - qemu_log("IN: %s\n", lookup_symbol(pc_start)); - log_target_disas(cs, pc_start, last_pc + 4 - pc_start, 0); - qemu_log("\n"); - } -#endif -} - -void gen_intermediate_code_init(CPUSPARCState *env) -{ - static int inited; - static const char gregnames[32][4] = { - "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7", - "o0", "o1", "o2", "o3", "o4", "o5", "o6", "o7", - "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7", - "i0", "i1", "i2", "i3", "i4", "i5", "i6", "i7", - }; - static const char fregnames[32][4] = { - "f0", "f2", "f4", "f6", "f8", "f10", "f12", "f14", - "f16", "f18", "f20", "f22", "f24", "f26", "f28", "f30", - "f32", "f34", "f36", "f38", "f40", "f42", "f44", "f46", - "f48", "f50", "f52", "f54", "f56", "f58", "f60", "f62", - }; - - static const struct { TCGv_i32 *ptr; int off; const char *name; } r32[] = { -#ifdef TARGET_SPARC64 - { &cpu_xcc, offsetof(CPUSPARCState, xcc), "xcc" }, - { &cpu_asi, offsetof(CPUSPARCState, asi), "asi" }, - { &cpu_fprs, offsetof(CPUSPARCState, fprs), "fprs" }, - { &cpu_softint, offsetof(CPUSPARCState, softint), "softint" }, -#else - { &cpu_wim, offsetof(CPUSPARCState, wim), "wim" }, -#endif - { &cpu_cc_op, offsetof(CPUSPARCState, cc_op), "cc_op" }, - { &cpu_psr, offsetof(CPUSPARCState, psr), "psr" }, - }; - - static const struct { TCGv *ptr; int off; const char *name; } rtl[] = { -#ifdef TARGET_SPARC64 - { &cpu_gsr, offsetof(CPUSPARCState, gsr), "gsr" }, - { &cpu_tick_cmpr, offsetof(CPUSPARCState, tick_cmpr), "tick_cmpr" }, - { &cpu_stick_cmpr, offsetof(CPUSPARCState, stick_cmpr), "stick_cmpr" }, - { &cpu_hstick_cmpr, offsetof(CPUSPARCState, hstick_cmpr), - "hstick_cmpr" }, - { &cpu_hintp, offsetof(CPUSPARCState, hintp), "hintp" }, - { &cpu_htba, offsetof(CPUSPARCState, htba), "htba" }, - { &cpu_hver, offsetof(CPUSPARCState, hver), "hver" }, - { &cpu_ssr, offsetof(CPUSPARCState, ssr), "ssr" }, - { &cpu_ver, offsetof(CPUSPARCState, version), "ver" }, -#endif - { &cpu_cond, offsetof(CPUSPARCState, cond), "cond" }, - { &cpu_cc_src, offsetof(CPUSPARCState, cc_src), "cc_src" }, - { &cpu_cc_src2, offsetof(CPUSPARCState, cc_src2), "cc_src2" }, - { &cpu_cc_dst, offsetof(CPUSPARCState, cc_dst), "cc_dst" }, - { &cpu_fsr, offsetof(CPUSPARCState, fsr), "fsr" }, - { &cpu_pc, offsetof(CPUSPARCState, pc), "pc" }, - { &cpu_npc, offsetof(CPUSPARCState, npc), "npc" }, - { &cpu_y, offsetof(CPUSPARCState, y), "y" }, -#ifndef CONFIG_USER_ONLY - { &cpu_tbr, offsetof(CPUSPARCState, tbr), "tbr" }, -#endif - }; - - unsigned int i; - - /* init various static tables */ - if (inited) { - return; - } - inited = 1; - - cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env"); - - cpu_regwptr = tcg_global_mem_new_ptr(cpu_env, - offsetof(CPUSPARCState, regwptr), - "regwptr"); - - for (i = 0; i < ARRAY_SIZE(r32); ++i) { - *r32[i].ptr = tcg_global_mem_new_i32(cpu_env, r32[i].off, r32[i].name); - } - - for (i = 0; i < ARRAY_SIZE(rtl); ++i) { - *rtl[i].ptr = tcg_global_mem_new(cpu_env, rtl[i].off, rtl[i].name); - } - - TCGV_UNUSED(cpu_regs[0]); - for (i = 1; i < 8; ++i) { - cpu_regs[i] = tcg_global_mem_new(cpu_env, - offsetof(CPUSPARCState, gregs[i]), - gregnames[i]); - } - - for (i = 8; i < 32; ++i) { - cpu_regs[i] = tcg_global_mem_new(cpu_regwptr, - (i - 8) * sizeof(target_ulong), - gregnames[i]); - } - - for (i = 0; i < TARGET_DPREGS; i++) { - cpu_fpr[i] = tcg_global_mem_new_i64(cpu_env, - offsetof(CPUSPARCState, fpr[i]), - fregnames[i]); - } -} - -void restore_state_to_opc(CPUSPARCState *env, TranslationBlock *tb, - target_ulong *data) -{ - target_ulong pc = data[0]; - target_ulong npc = data[1]; - - env->pc = pc; - if (npc == DYNAMIC_PC) { - /* dynamic NPC: already stored */ - } else if (npc & JUMP_PC) { - /* jump PC: use 'cond' and the jump targets of the translation */ - if (env->cond) { - env->npc = npc & ~3; - } else { - env->npc = pc + 4; - } - } else { - env->npc = npc; - } -} diff --git a/qemu/target-sparc/vis_helper.c b/qemu/target-sparc/vis_helper.c deleted file mode 100644 index 8a9b763d0..000000000 --- a/qemu/target-sparc/vis_helper.c +++ /dev/null @@ -1,490 +0,0 @@ -/* - * 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; -} diff --git a/qemu/target-sparc/win_helper.c b/qemu/target-sparc/win_helper.c deleted file mode 100644 index a8a6c0cfc..000000000 --- a/qemu/target-sparc/win_helper.c +++ /dev/null @@ -1,399 +0,0 @@ -/* - * 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/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) { - helper_raise_exception(env, TT_ILL_INSN); - } - - env->psret = 1; - cwp = cpu_cwp_inc(env, env->cwp + 1) ; - if (env->wim & (1 << cwp)) { - helper_raise_exception(env, TT_WIN_UNF); - } - 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)) { - helper_raise_exception(env, TT_WIN_OVF); - } - 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)) { - helper_raise_exception(env, TT_WIN_UNF); - } - cpu_set_cwp(env, cwp); -} - -void helper_wrpsr(CPUSPARCState *env, target_ulong new_psr) -{ - if ((new_psr & PSR_CWP) >= env->nwindows) { - helper_raise_exception(env, TT_ILL_INSN); - } 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) { - helper_raise_exception(env, TT_SPILL | (env->otherwin != 0 ? - (TT_WOTHER | - ((env->wstate & 0x38) >> 1)) : - ((env->wstate & 0x7) << 2))); - } else { - if (env->cleanwin - env->canrestore == 0) { - /* XXX Clean windows without trap */ - helper_raise_exception(env, TT_CLRWIN); - } 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) { - helper_raise_exception(env, TT_FILL | (env->otherwin != 0 ? - (TT_WOTHER | - ((env->wstate & 0x38) >> 1)) : - ((env->wstate & 0x7) << 2))); - } else { - env->cansave++; - env->canrestore--; - cpu_set_cwp(env, cwp); - } -} - -void helper_flushw(CPUSPARCState *env) -{ - if (env->cansave != env->nwindows - 2) { - helper_raise_exception(env, TT_SPILL | (env->otherwin != 0 ? - (TT_WOTHER | - ((env->wstate & 0x38) >> 1)) : - ((env->wstate & 0x7) << 2))); - } -} - -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 |